IMHO, for messages that are very likely to be displayed, such as those given to error
or warn
it does not make much of a difference.
For messages that are less likely displayed, I would definitely go for the second version, mainly for performance reasons. I often give large objects as a parameter to info
, which implement a costly __str__
method. Clearly, sending this pre-formatted to info
would be a performance waste.
UPDATE
I just checked the source code of the logging
module and, indeed, formatting is done after checking the log level. For example:
class Logger(Filterer):
# snip
def debug(self, msg, *args, **kwargs):
# snip
if self.isenabledfor(debug):
self._log(debug, msg, args, **kwargs)
One can observe that msg
and args
are untouched between calling log
and checking the log level.
UPDATE 2
Spired by Levon, let me add some tests for objects that have a costly __str__
method:
$ python -m timeit -n 1000000 -s "import logging" -s "logger = logging.getLogger('foo')" -s "logger.setLevel(logging.ERROR)" "logger.warn('%s', range(0,100))"
1000000 loops, best of 3: 1.52 usec per loop
$ python -m timeit -n 1000000 -s "import logging" -s "logger = logging.getLogger('foo')" -s "logger.setLevel(logging.ERROR)" "logger.warn('%s' % range(0,100))"
1000000 loops, best of 3: 10.4 usec per loop
In practice, this could give a fairly high performance boost.