2

I have a script which different people may use. I have print statements so people can follow along what the script is doing, and if it breaks where it went wrong, and if a certain step takes a long time which step it was.

Which way for print statements is better in this case and why?

This:

def do_something():
    ...

print 'doing something'
do_something()

Or this:

def do_something():
    print 'doing something'
    ...

do_something()

I am inclined to think the first is better as it is slightly clearer what is going on when people look at your script; they know there is a print statement before the function is called, and you can add extra detail when sometimes the function name isn't as informative as it could be.

However I see how it could be considered duplication of code. And so the second is better.

But more important than this quite specific question is what general principle would lead you to prefer one over the other?

closed as primarily opinion-based by GlenH7, user22815, Kilian Foth, Dan Pichelman, gnat Nov 10 '14 at 16:36

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.

  • Sharing your research helps everyone. Tell us what you've tried and why it didn’t meet your needs. This demonstrates that you’ve taken the time to try to help yourself, it saves us from reiterating obvious answers, and most of all it helps you get a more specific and relevant answer. Also see How to Ask – gnat Nov 7 '14 at 16:16
  • 4
    What are you trying to accomplish with those print statements? You may be asking the wrong question. – user22815 Nov 7 '14 at 16:25
  • I have a script which different people may use. I have print statements so people can follow along what the script is doing, and if it breaks where it went wrong, and if a certain step takes a long time which step it was. – Will Beauchamp Nov 7 '14 at 16:31
  • 2
    Is that necessary to build in? Who will be using it? If it breaks the traceback will tell you where, and if you want to find bottlenecks you should profile it. – jonrsharpe Nov 7 '14 at 16:52
  • one may argue that conceptually, this has been addressed in How would you know if you've written readable and easily maintainable code? If your peers keep complaining about your way of doing things, be it one way or another, you better change to make them feel better – gnat Nov 7 '14 at 16:59
7

Note: don't use print for logging purposes. Using print may work for small applications, but when the application starts increasing, moving to the actual logging would quickly become unavoidable. To avoid future maintenance cost, consider using logging from the beginning. Make sure you use existent predefined logging frameworks and don't reinvent the wheel.


Is the print statement part of the function? In other words, does it make sense to run the function without the print statement?

If the specific statement is inherent to the function, put it inside. If the specific statement is inherent to the context of the caller, put it there.

Example:

def add_product(product):
    logger.debug("The product %s is about to be added to the database.", product.id)
    ...

Here, the logging is inherent to the function: it doesn't matter when and where the function was called, so whenever it is, the log entry should be added.

def add_product(product):
    ...

logger.debug("Adding the product %s created by the administrator.", product.id)
add_product(self.newProduct)

Here, on the other hand, the context is important: the log message indicates why the product is being added to the database—it is added because the administrator just created it. Thus, the message makes no sense within the function.

  • I don't agree with your answer. It is certainly better than the OPs approach but it still is conflicting with the SRP. The function add_product should do what it says: add a product. Not add a product and log something. Even worse: where does the log function come from? Is it global? This makes the function behave on global state and therefore harder to test and harder to reason about. If no AOP is possible, I would suggest to at least remove the logging from add_product and make a add_product_and_log(product, logger) that adds the product and logs the action. – valenterry Nov 8 '14 at 0:01
  • 1
    I don't think names such as add_product_and_log are a sustainable solution. In large applications, nearly every function logs something (most at verbose level); you wouldn't suffix every name by _and_log, would you? – Arseni Mourzenko Nov 8 '14 at 10:40
  • I agree, log function shouldn't be global. I did it this way for the sake of simplicity, but indeed, it is important to note that one should use a logging framework instead of inventing his own logging functions. – Arseni Mourzenko Nov 8 '14 at 10:40
  • using *_and_log functions is only a workaround for the underlying problem that no AOP can be used. If, however, the logging is part of the functional features of the program, then it should be named like it (or beeing encapsulated in a decorator). – valenterry Nov 10 '14 at 11:48
2

There is better ways to enable your users to follow the scripts actions. One way is to return an object that describes what steps happend, what the result is and how long the steps took. If it breaks, you should throw an exception which includes additional information.

Another way to do this is using AOP features. These are however not builtin python and you have little IDE support when using reflection/introspection to achieve the desired AOP behaviour. The advantage is, that your logging code and the functional code is seperated and the logging can be enabled and disabled or even extended without having to touch the functional code.

If you want to use neither of these solutions, at least make your users to be able to inject a service that is used for printing, so they can decide what the service should do with your messages. It is really bad if you are using a third-party script and the script just prints to stdout or stderr. You then have to do dirty piping stuff to prevent unwanted output.

Not the answer you're looking for? Browse other questions tagged or ask your own question.