Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to specify float precision from variable in logging using % formatting?

I want to avoid the eager evaluation of f-strings in logging, therefore I use %-formatting.

The precision is defined by a variable precision.

import logging
value = 3.14159
logging.error("%.2f", value)

precision = 2

logging.error(f"{value:.{precision}f}") # OK but eager evaluation
logging.error("%.*f", value, precision) # fails
logging.error("%.%if", value, precision) # fails

Any suggestion?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

logging.error("%.*f", value, precision) # fails

is almost correct, but the precision has to come first:

logging.error("%.*f", precision, value) # works

Mnemonic: The placeholder * for precision comes before the placeholder f for the float value, so the precision is provided before the float.


Sadly, while the mnemonic applies in other formatting tools, it’s applied to the beginning of each placeholder, not the end. For example, in str.format, the auto-numbering of placeholders is based on the order of the open brace { for each placeholder, so for that case, you’d do:

'{:.{}f}'.format(value, precision)

since the open brace for the placeholder for value comes before the open brace placeholder for precision. Of course, in that case, you can avoid ambiguity by being explicit and numbering them:

'{0:.{1}f}'.format(value, precision)

or naming them:

'{value:.{precision}f}'.format(precision=precision, value=value)  # Order of kwargs irrelevant

With f-strings of course, you inline the names being used in each place so no confusion exists:

f'{value:.{precision}f}'

and it’s faster than any other means of string formatting in modern Python, so for any logs likely to actually get emitted in normal use, I’d just stick with the f-strings. Even for ones that won’t get emitted, the overhead of logging stuff that’s below the logging level (and doesn’t get emitted) is high enough that the savings from avoiding the temporary str are pretty minimal in context, and the risk of a mistake that isn’t noticed unless logging is turned up is high enough, that I’d typically use eager formatting, especially for more complicated cases like this. I’ve definitely been bitten by code of the form:

 logging.debug('%s %s', a, b, c)

where the code was executed unconditionally, but never with DEBUG level logging enabled; the first time I needed it to figure out a problem, the code broke due to the mismatched placeholder counts. A similar problem is impossible with eager formatting, whether it is modern f-strings or less modern str.format or even eager printf-style formatting like logging.debug('%s %s' % (a, b, c)); you’d see the error even if logging was turned off entirely.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading