[Python-ideas] String Format Callable Flag (Was: Efficient Debug Logging)

Steven D'Aprano steve at pearwood.info
Sat Feb 18 02:25:43 EST 2017

On Fri, Feb 17, 2017 at 11:37:04AM -0500, Mark E. Haase wrote:

> Python has two string formatting mini-languages.

Four. % string formatting, .format method, f-strings, string.Template 

But who's counting? :-)

> Both allow formatting
> flags, for example in "%03d", the "0" (zero) is a flag that means to pad
> with leading zeroes. I propose to add a string format flag to both
> mini-languages that explicitly says, "this argument is callable, and its
> *return value* should be formatted."

The % string format codes are intentionally limited to more-or-less the 
similar codes available in C, and won't be given any newer functionality.

It's really only f-strings and .format method that this change could be 
applied to.

> The suggested change is to add a "C" flag to the formatting language that
> indicates an argument is callable. When formatting the string, the argument
> will be called and its result will be used for the formatting operation.
> The C flag must be handled before any other flags, regardless of the order
> in which they are specified. The callable's return value is then formatted
> according to the rest of the specifier.
> With this change, the above example can now be written as:
>     >>> expensive = lambda: 2
>     >>> logging.debug('%03d %C03d', 1, expensive)
> The "expensive" code is not executed at this log level.

I see three problems:

(1) It will be a bug magnet. People will accidently write

    logging.debug('%03d %C03d', 1, expensive())

and then not only will their code still be slow, but they'll have to 
debug mysterious 

    TypeError: 'int' object is not callable

exceptions, but only *sometimes*. Most insideously, these Heisenbugs 
will only occur when they turn the log level all the way up to 
debugging, which will crash their program *before* logging the error!

(2) It requires the expensive calculation to be wrapped in a lambda:

    logging.debug('%03d %C03d', 1, lambda: nth_prime(10**8) + 1)

which I guess is kind of Python's way of spelling a thunk, but people 
don't like using lambda for that.

(3) It is useless for delaying evaluation of something that isn't going 
to be converted into a string.


More information about the Python-ideas mailing list