Skip to content Skip to sidebar Skip to footer

Conditionally Evaluated Debug Statements In Python

Python has a few ways of printing 'trace' output. print, import logging, stdout.write can be used to print debugging info, but they all have one drawback: even if the logger's thre

Solution 1:

if all your debug function will take is a string, why not change it to take a format string and the arguments:

debug(lambda:"Working on {0}".format(currentItem))

becomes

debug("Working on {0}", currentItem)

and

if__debug__:
    defdebug(format, *values):
        printformat.format(*values)
else:
    defdebug(format, *values): pass

this has all the advantages of your first option without the need for a lambda and if the if __debug__: is moved out the of function so that it is only tested once when the containing module is loaded the overhead of the statement is just one function call.

Solution 2:

I wonder how much a call to logging.debug impacts the performance when there are no handlers.

However the if __debug__: statement is evaluated only once, even in the body of a function

$ python -O
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>import dis>>>import logging>>>defdebug(*a, **kw):...if__debug__:...  logging.debug(*a, **kw)...>>>dis.dis(debug)
  2           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE        
>>>

and the logger can format the message for you using the string formatting operator. Here a slightly modified example taken from the logging.debug documentation

FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT)
d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' }
debug('Protocol problem: %s', 'connection reset', extra=d)

In this case the message string is never evaluated if the optimizations are turned off.

Solution 3:

any standard python statements or function with the same conditional behavior as assert -> no, as far as I know.

Note that no string interpolation is performed by logging functions if the threshold is too high (but you still pay for the method call and some of the checks inside).

You can expand on Dan D.'s suggestion by monkeypatching logging.logger when you code starts:

import logging
if__debug__:
    for methname in ('debug', 'info', 'warning', 'error', 'exception'):
         logging.logger.setattr(methname, lambda self, *a, **kwa: None)

and then use logging as usual. You can even change the initial test to allow the replacement of the logging methods even in non optimized mode

Solution 4:

You could use the eval method:

import inspect

defdebug(source):
  if__debug__:
    callers_locals = inspect.currentframe().f_back.f_locals
    printeval(source, globals(),  callers_locals)

for currentItem in ('a', 'b'):
  debug('"Working on {0}".format(currentItem)')

Post a Comment for "Conditionally Evaluated Debug Statements In Python"