Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does `str.format()` ignore additional/unused arguments?

I saw "Why doesn't join() automatically convert its arguments to strings?" and the accepted answer made me think: since

Explicit is better than implicit.

and

Errors should never pass silently.

why does str.format() ignore additional/unused (sometimes accidentally passed) arguments? To me it looks like an error which is passed silently, and it surely isn't explicit:

>>> 'abc'.format(21, 3, 'abc', object(), x=5, y=[1, 2, 3])
'abc'

This actually lead my friend to an issue with os.makedirs(path, exist_ok=True) still raising an error even though the docs for os.makedirs() said that exist_ok=True won't raise an error even if path already exists. It turned out he just had a long line with nested function calls, and the exist_ok was passed in to a nested .format() call instead of the os.makedirs().

like image 960
Markus Meskanen Avatar asked Jul 13 '16 11:07

Markus Meskanen


People also ask

What is format map in Python?

Python String format_map() method is an inbuilt function in Python, which is used to return a dictionary key's value. Syntax: string.format_map(z) Parameters: Here z is a variable in which the input dictionary is stored and string is the key of the input dictionary.

Are F strings faster Python?

As of Python 3.6, f-strings are a great new way to format strings. Not only are they more readable, more concise, and less prone to error than other ways of formatting, but they are also faster!

How to fix not enough arguments for format string?

To solve this problem, first ensure you enclose all arguments in curly brackets () if you are using the % operator. You can use the . format() method as a replacement for the % syntax if you want to fix this error and modernize your code.


1 Answers

Ignoring un-used arguments makes it possible to create arbitrary format strings for arbitrary-sized dictionaries or objects.

Say you wanted to give your program the feature to let the end-user change the output. You document what fields are available, and tell users to put those fields in {...} slots in a string. The end-user then can create templating strings with any number of those fields being used, including none at all, without error.

In other words, the choice is deliberate, because there are practical reasons for allowing more arguments than are converted. Note that the C# String.Formatter implementation that inspired the Python PEP does the same, for those same reasons.

Not that the discussion on this part of the PEP is that clear cut; Guido van Rossum at some point tries to address this issue:

The PEP appears silent on what happens if there are too few or too many positional arguments, or if there are missing or unused keywords. Missing ones should be errors; I'm not sure about redundant (unused) ones. On the one hand complaining about those gives us more certainty that the format string is correct. On the other hand there are some use cases for passing lots of keyword parameters (e.g. simple web templating could pass a fixed set of variables using **dict). Even in i18n (translation) apps I could see the usefulness of allowing unused parameters

to which the PEP author responded that they were still undecided on this point.

For use-cases where you must raise an exception for unused arguments you are expected to subclass the string.Formatter() class and provide an implementation for Formatter.check_unused_args(); the default implementation does nothing. This of course doesn't help your friend's case where you used str.format(*args, **kwargs) rather than Formatter().format(str, *args, **kwargs). I believe that at some point the idea was that you could replace the formatter used by str.format() with a custom implementation, but that never came to pass.

If you use the flake8 linter, then you can add the flake8-string-format plugin to detect the obvious cases, where you passed in an explicit keyword argument that is not being used by the format string.

like image 172
Martijn Pieters Avatar answered Oct 11 '22 18:10

Martijn Pieters