Почему `str.format()` игнорирует дополнительные/неиспользуемые аргументы?

Я видел "Почему не join() автоматически конвертирует свои аргументы в строки?" и принятый ответ заставлял меня думать: поскольку

Явный лучше, чем неявный.

и

Ошибки никогда не должны проходить молча.

почему str.format() игнорирует дополнительные/неиспользуемые (иногда случайно переданные) аргументы? Для меня это выглядит как ошибка, которая передается молча, и она явно не является явной:

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

Это действительно приводит моего друга к проблеме с os.makedirs(path, exist_ok=True), все еще вызывающей ошибку, хотя документы для os.makedirs() говорят, что exist_ok=True не приведет к ошибке, даже если path уже существует. Оказалось, что у него просто была длинная строка с вложенными вызовами функций, а exist_ok была передана вложенному вызову .format() вместо os.makedirs().

Ответ 1

Игнорирование неиспользуемых аргументов позволяет создавать произвольные строки формата для словарей или объектов произвольного размера.

Предположим, что вы хотите предоставить своей программе функцию, позволяющую конечному пользователю изменить выход. Документируйте, какие поля доступны, и сообщите пользователям, чтобы они помещали эти поля в {...} слоты в строке. Затем конечный пользователь может создавать шаблонные строки с любым количеством используемых полей, в том числе без них, без ошибок.

Иными словами, выбор преднамерен, потому что есть практические причины для предоставления большего количества аргументов, чем преобразованные. Обратите внимание, что реализация С# String.Formatter, которая вдохновила PEPP PEP, делает то же самое по тем же причинам.

Не то, чтобы обсуждение этой части ОПТОСОЗ заключалось в том, что четкое сокращение; Гвидо ван Россум в какой-то момент пытается решить эту проблему:

В PEP не говорится о том, что происходит, если слишком мало или слишком многие позиционные аргументы, или если отсутствуют или не используются ключевые слова. Отсутствующие должны быть ошибки; Я не уверен в избыточности (не используется) из них. С одной стороны, жалобы на них дают нам больше уверенности что строка формата верна. С другой стороны, есть некоторые использование случаев для передачи множества параметров ключевых слов (например, простой веб-сайт templating может передать фиксированный набор переменных, используя ** dict). Даже в Приложения i18n (перевод) Я мог видеть полезность разрешения неиспользуемых Параметры

на который автор PEP ответил, что они еще не определились по этому вопросу.

В случаях использования, где вы должны создать исключение для неиспользуемых аргументов, вы должны подклассифицировать класс string.Formatter() и предоставить реализацию для Formatter.check_unused_args(); реализация по умолчанию ничего не делает. Это, конечно, не поможет вашему другу, где вы использовали str.format(*args, **kwargs), а не Formatter().format(str, *args, **kwargs). Я считаю, что в какой-то момент идея заключалась в том, что вы могли заменить форматировщик, используемый str.format(), с помощью специальной реализации, но это никогда не происходило.

Если вы используете flake8 linter, вы можете добавить плагин flake8-string-format в обнаружите очевидные случаи, когда вы передали явный аргумент ключевого слова, который не используется в строке формата.