<div dir="ltr">In the debug logging thread, somebody suggested the "%r" format specifier and a custom __repr__. This is a neat solution because Python logging already includes a "delayed" evaluation of sorts: it formats the logging string *after* it determines that the message's log level is greater than or equal to the logger's level. However, wrapping up every expensive debugging computation in a new class might get tedious, so here's a strawman proposal for something lighter weight. <div><br></div><div>Python has two string formatting mini-languages. 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."</div><div><br></div><div>In current Python:</div><div><br></div><div><div>    >>> expensive = lambda: 2</div><div>    >>> logging.debug('%03d %03d', 1, expensive())<br></div><div><br></div><div>In this case, the "expensive" code is executed even though nothing is logged.</div><div><br></div><div><div>    >>> expensive = lambda: 2</div><div>    >>> logging.root.setLevel(logging.<wbr>DEBUG)</div><div>    >>> logging.debug('%03d %03d', 1, expensive())</div><div>    DEBUG:root:001 002</div></div></div><div><br></div><div>With a different log level, the expensive code is executed and the message is logged.</div><div><br></div><div>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.</div><div><br></div><div>With this change, the above example can now be written as:</div><div><br></div><div><div><div><div>    >>> expensive = lambda: 2</div><div>    >>> logging.debug('%03d %C03d', 1, expensive)</div></div><div><br></div><div>The "expensive" code is not executed at this log level.</div><div><br></div><div>    >>> expensive = lambda: 2</div><div>    >>> logging.root.setLevel(logging.<wbr>DEBUG)</div><div>    >>> logging.warn('%03d %C03d', 1, expensive)</div><div>    WARNING:root:001 002</div></div></div><div><br></div><div>The expensive code is *only* executed when the message will be logged. The callable's return value is formatted with the specifier '%03d', i.e. the same specifier as the callable but without the "C" flag.</div><div><br></div><div><br></div><div><br></div><div>Pros:</div><div><br></div><div>1) Much smaller change to the language.</div><div>2) Simplifies a common (?) problem with logging.</div><div>3) Applies to all string formatting, not just logging. (But I'm not sure what the other use cases are.)</div><div><br></div><div>Cons:</div><div><br></div><div>1) Doesn't generalize as well as the various "delayed" proposals. (But I'm not sure what other use cases "delayed" has.)</div></div>