I’m running into a performance problem in a project, and I narrowed it down to some of the log lines. It seems that f-strings are calculated even when my logging facility is above the level of the line that is logging.

Consider this example to demonstrate the issue:

import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('MyLogger')

class MyClass:
    def __init__(self, name: str) -> None:
        self._name = name
    def __str__(self) -> str:
        print('GENERATING STRING')
        return self._name

c = MyClass('foo')
logger.debug(f'Created: {c}')

When this example is run, I get “GENERATING STRING” printed to screen, indicating that the __str__ method is being ran even though my logging level is set to INFO and the log line is for DEBUG.

From what I can tell today, the solution is to use the following vs an f-string.

logger.debug('Created: %s', c)

There are three things going through my head right now.

  • Most of the examples and docs I read seem to be pretty old.
  • This project is Python 3.7+ only (not worried about being backwards compatible).
  • I have a lot of lines of code to update.

I’m curious to know what others do in this situation. Is the %s the best (most modern) approach? Is there a more modern way that I should be logging as demonstrated above?

I have a lot of code to update (fix), and I’m hoping to align with modern best practices.

The documentation says that the logging lib is optimized to use the %s formatting style. I can’t remember where it is mentionned exactly, but I read it a few months ago.

Edit – Found! https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles
Edit2(thanks to Robin Nemeth): https://docs.python.org/3/howto/logging.html#optimization

IMO, using %s in your strings is NOT the most modern approach. Definitely, most developers will prefer to use f-strings because it is more convenient and easy to read (and write).

But, you interestingly find a specific case where you may not want to use an f-string. If you need to avoid automatic call of __str__() method because of optimisation issue, then it is probably a good enough reason to use %s instead of f-strings. But, this could also indicate that something may be done in your program to reduce the complexity of __str__(). Most of the time it shouldn’t take so much time or resources to calculate a string representation for an object…