Skip to content

W1202 - logging-fstring-interpolation is not useful #2395

@pzelnip

Description

@pzelnip

Is your feature request related to a problem? Please describe

In my experiments W1202 is misleading as f-strings performance is virtually equivalent to %-operator formatting in practice.

Describe the solution you'd like

W1202 be deprecated, as it can lead people to not use f-strings, which (if available) are the preferred mechanism for string interpolation.

Additional context

This is related to my inquiry around this warning: #2354

To verify my hypothesis that f-strings are virtually as performant as %-operator formatting I wrote the following snippet to explore timing related to log statements with the 3 approaches (f-strings, .format(), and %-operator). This was on a Django app I'm working on.

import timeit

def timeitex1(num_times):
    fstring = timeit.timeit(
        'logging.info(f"""this is a {thing}, and thing: {thing + "blah"}""")',
        setup="import logging ; thing='1234'",
        number=num_times,
    )

    formattim = timeit.timeit(
        'logging.info("this is a {}, and thing: {}".format(thing, thing + "blah"))',
        setup="import logging ; thing='1234'",
        number=num_times,
    )

    percentop = timeit.timeit(
        'logging.info("this is a %s, and thing: %s", thing, thing + "blah")',
        setup="import logging ; thing='1234'",
        number=num_times,
    )

    return (fstring, formattim, percentop)

With logging output disabled (ie in my Django settings I had: LOGGING["loggers"] = {}), %-formatting and f-strings are virtually identical.

num_times = 10,000:
(0.016536445124074817, 0.02152163698337972, 0.018616185057908297)

num_times = 100,000:
(0.16004435811191797, 0.20005284599028528, 0.1561291899997741)

num_times = 1,000,000:
(1.641325417906046, 2.0023047979921103, 1.6249939629342407)

Returned times are tuples of "time for f-strings", "time for the format() call", and "time for %-formatting".

That's a difference of ~1% (1.641325417906046 vs 1.6249939629342407 seconds) between f-strings & the %-operator on the largest run (.format calls being clearly slower).

With logging enabled, it's a total wash (technically f-strings was the winner in the larger runs but by such a small margin it's inconsequential). This is with log output going to standard out (so I only went up to 100,000 entries as I didn't want to dump 3 million log statements to my console):

num_times = 10,000:
(1.6245153648778796, 2.0137458329554647, 1.6029843359719962)

num_times = 100,000:
(4.39409149507992, 4.51585376705043, 4.532764581032097)

So basically unless you are emitting a ton of logging statements for a level that are never actually logged (say because the LOG_LEVEL is set high), then it doesn't matter. And if you're in that scenario, then really there's no noticeable difference between %-operator formatting or f-strings (just don't do .format() calls).

OTOH, if you are emitting the logging message, then it's likely that the f-string approach will be faster, so following W1202 will actually make your code (extremely slightly) slower.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions