Почему в Python есть функция форматирования, а также метод форматирования

Функция format во встроенных функциях выглядит как подмножество _ 2_ метод, используемый специально для случая форматирования одного объекта.

eg.

>>> format(13, 'x')
'd'

очевидно предпочтительнее

>>> '{0:x}'.format(13)
'd'

И ИМО это выглядит лучше, но почему бы просто не использовать str.format в каждом случае, чтобы упростить задачу? Оба они были введены в 2.6, поэтому должна быть веская причина для одновременного использования обоих, что это?

Изменить: я спрашивал о str.format и format, а не о том, почему у нас нет (13).format


person jamylak    schedule 22.05.2013    source источник
comment
Эээ, я впервые слышу, как кто-то говорит, что format() предпочтительнее .format() - даже в документации по спецификациям строк формата везде используется .format(). Откуда вы берете это format() предпочтительнее?   -  person Amber    schedule 22.05.2013
comment
@Amber только из ответов здесь, на SO, которые всегда, похоже, используют его в этом случае   -  person jamylak    schedule 22.05.2013
comment
@Amber stackoverflow.com/ questions / 16414559 /   -  person jamylak    schedule 22.05.2013
comment
это кажется довольно неубедительным примером для вывода о предпочтительном стиле, особенно с учетом второго ответа на этот вопрос и обсуждения в комментариях. В качестве другого контрпримера см. stackoverflow.com/questions/1225637/python- форматирование строки /   -  person Amber    schedule 22.05.2013
comment
@Amber, в вашем связанном вопросе используется несколько замен, где работает только .format   -  person jamylak    schedule 22.05.2013
comment
Этот пример - ваш собственный ответ ... просто скажите: D   -  person wim    schedule 22.05.2013
comment
@wim Я подумал, что это может быть, но я хотел посмотреть, есть ли какой-нибудь окончательный ответ, поскольку большинство людей даже не знают о format   -  person jamylak    schedule 22.05.2013


Ответы (2)


Я думаю, что format и str.format делают разные вещи. Несмотря на то, что вы можете использовать str.format для обоих, имеет смысл иметь отдельные версии.

Функция верхнего уровня format является частью нового «протокола форматирования», который поддерживают все объекты. Он просто вызывает метод __format__ переданного объекта и возвращает строку. Это низкоуровневая задача, и стиль Python обычно заключается в наличии для нее встроенных функций. Ответ Пауло Скардина объясняет некоторые причины этого, но я не думаю, что он действительно учитывает различия между тем, что делают format и str.format.

Метод str.format немного более высокоуровневый, но и более сложный. Он может не только форматировать несколько объектов в один результат, но также может изменять порядок, повторять, индексировать и выполнять различные другие преобразования объектов. Не думайте только о "{}".format(obj). str.format действительно предназначен для решения более сложных задач, таких как:

"{1} {0} {1!r}".format(obj0, obj1) # reorders, repeats, and and calls repr on obj1
"{0.value:.{0.precision}f}".format(obj) # uses attrs of obj for value and format spec
"{obj[name]}".format(obj=my_dict) # takes argument by keyword, and does an item lookup

Для низкоуровневого форматирования каждого элемента str.format полагается на тот же механизм, что и протокол форматирования, поэтому он может сосредоточить свои собственные усилия на материалах более высокого уровня. Я сомневаюсь, что он на самом деле вызывает встроенные format, а не __format__ методы своих аргументов, но это деталь реализации.

Хотя ("{:"+format_spec+"}").format(obj) гарантированно даст те же результаты, что и format(obj, format_spec), я подозреваю, что последний будет немного быстрее, поскольку ему не нужно анализировать строку формата для проверки каких-либо сложных вещей. Однако в реальной программе накладные расходы могут быть потеряны из-за шума.

Когда дело доходит до использования (включая примеры в Stack Overflow), вы можете увидеть больше str.format использования просто потому, что некоторые программисты не знают о format, которое одновременно ново и довольно малоизвестно. Напротив, этого трудно избежать str.format (если вы не решили придерживаться оператора % для всего вашего форматирования). Таким образом, легкость (для вас и ваших коллег-программистов) понимания str.format вызова может перевесить любые соображения производительности.

person Blckknght    schedule 22.05.2013
comment
Пауло приложил много усилий, чтобы ответить, и он выглядит как одно из тех всеобъемлющих руководств. Однако он отвечает на несуществующий вопрос. Я хотел знать, почему мы не всегда просто используем '{0}'.format. Да, я понимаю, что format() является синтаксическим сахаром для __format__, и Пауло много говорил о том, почему это хорошо для Python. Но это не мой вопрос. Ваш ответ объясняет почему и имеет логический смысл. Я не согласен с тем, что у Python есть обе версии, потому что он противоречит одному способу сделать это мантрой, ну да ладно. Я сделаю это простым, используя только формат "{0}". - person jamylak; 28.06.2015

tldr; format просто вызывает obj.__format__ и используется str.format методом, который выполняет еще более высокоуровневые функции. Для нижнего уровня имеет смысл научить объект форматироваться.

Это просто синтаксический сахар

Тот факт, что эта функция разделяет имя и спецификацию формата с str.format, может вводить в заблуждение. Существование str.format легко объяснить: он выполняет сложную интерполяцию строк (заменяя старый оператор %); format может форматировать отдельный объект как строку, наименьшее подмножество str.format спецификации. Итак, зачем нам format?

Функция format является альтернативой конструкции obj.format('fmt'), которая есть в некоторых языках OO. Это решение согласуется с обоснованием len (почему Python использует функцию len(x) вместо свойства x.length, например Javascript или Ruby).

Когда язык принимает конструкцию obj.format('fmt') (или obj.length, obj.toString и т. Д.), Классы не могут иметь атрибут с именем format (или length, toString, вы уловили идею) - в противном случае он бы затенял стандартный метод языка. В этом случае разработчики языка перекладывают бремя предотвращения конфликтов имен на программиста.

Python очень любит PoLA и принял соглашение __dunder__ (двойное подчеркивание) для встроенных в чтобы свести к минимуму вероятность конфликтов между определяемыми пользователем атрибутами и встроенными языками. Итак, obj.format('fmt') становится obj.__format__('fmt'), и, конечно, вы можете вызвать obj.__format__('fmt') вместо format(obj, 'fmt') (точно так же вы можете вызвать obj.__len__() вместо len(obj)).

Используя ваш пример:

>>> '{0:x}'.format(13)
'd'
>>> (13).__format__('x')
'd'
>>> format(13, 'x')
'd'

Какой из них чище и легче набирать? Дизайн Python очень прагматичен, он не только чище, но и хорошо согласуется с утиным типом в Python. подход к OO и дает разработчикам языка свободу изменять / расширять базовую реализацию без нарушения устаревшего код.

PEP 3101 представил новый метод str.format и встроенный format без каких-либо комментариев. в обосновании функции format, но реализация, очевидно, представляет собой просто синтаксический сахар:

def format(value, format_spec):
    return value.__format__(format_spec)

И здесь я отдыхаю.

Что Гвидо сказал по этому поводу (или это официально?)

Цитата из самого BDFL о len:

Прежде всего, я выбрал len(x) вместо x.len() по причинам HCI (пришло def __len__() гораздо позже). На самом деле есть две взаимосвязанные причины, обе HCI:

(a) Для некоторых операций префиксная нотация просто читается лучше, чем постфиксная - префиксные (и инфиксные!) операции имеют давнюю традицию в математике, которой нравятся нотации, в которых визуальные элементы помогают математику думать о проблеме. Сравните легкость, с которой мы переписываем формулу типа x*(a+b) в x*a + x*b, с неуклюжестью выполнения того же самого с использованием необработанной объектно-ориентированной нотации.

(б) Когда я читаю код, который говорит len(x), я знаю, что он запрашивает длину чего-то. Это говорит мне о двух вещах: результат - целое число, а аргумент - это своего рода контейнер. Напротив, когда я читаю x.len(), я уже должен знать, что x - это своего рода контейнер, реализующий интерфейс или наследующий от класса, имеющего стандартный len(). Обратите внимание на путаницу, которая иногда возникает, когда класс, не реализующий сопоставление, имеет get() или keys() метод, или что-то, что не является файлом, имеет метод write().

Говоря то же самое по-другому, я вижу "len" как встроенную операцию. Я бы не хотел это потерять. /… /

источник: [email protected] (исходное сообщение здесь также есть исходный вопрос, на который отвечал Гвидо). Абарнерт также предлагает:

Дополнительные аргументы относительно len в Часто задаваемые вопросы по дизайну и истории. Хотя это не такой полный или хороший ответ, он, бесспорно, официальный. - abarnert

Это практическая проблема или просто придирки к синтаксису?

Это очень практичная и реальная проблема для таких языков, как Python, Ruby или Javascript, потому что в динамически типизированных языках любой изменяемый объект фактически является пространством имен, а концепция частных методов или атрибутов является предметом соглашения. Возможно, я не смог бы выразить это лучше, чем abarnert в его комментарии:

Кроме того, что касается проблемы загрязнения пространства имен Ruby и JS, стоит отметить, что это неотъемлемая проблема языков с динамической типизацией. В таких разнообразных статически типизированных языках, как Haskell и C ++, бесплатные функции для конкретных типов не только возможны, но и идиоматичны. (См. принцип интерфейса.) Но в языках с динамической типизацией, таких как Ruby, JS и Python, бесплатные функции должны быть универсальными. Большая часть дизайна языка / библиотеки для динамических языков - это выбор правильного набора таких функций.

Например, я просто оставил Ember.js в пользу Angular.js, потому что мне надоело конфликты пространств имен в Ember; Angular обрабатывает это, используя элегантную стратегию, похожую на Python, с добавлением префиксов к встроенным методам (с $thing в Angular вместо подчеркивания, как в python), поэтому они не конфликтуют с пользовательскими методами и свойствами. Да, в целом __thing__ не особо красив, но я рад, что Python использовал этот подход, потому что он очень явный и избегает PoLA класс ошибок, связанных с конфликтами пространств имен объектов.

person Community    schedule 22.05.2013
comment
Я бы не сказал, что эти два случая абсолютно одинаковы ('{0}'.format не то же самое, что x.len, в некотором смысле похоже на ''.join), но я понимаю, откуда вы пришли, и это имеет смысл. - person jamylak; 22.05.2013
comment
@jamylak: в некоторых объектно-ориентированных языках каждый объект должен иметь метод форматирования, например obj.format('fmt'). Вместо этого в Python предпочтительнее была форма format(obj, 'fmt'). Таким образом, эта функция не является частным случаем str.format, несмотря на то, что имя и спецификация формата совпадают. - person Paulo Scardine; 22.05.2013
comment
Я знаю, но '{0}'.format также вызывает .__format__ объекта точно так же, как format() - person jamylak; 22.05.2013
comment
таким же образом len(x) может вызывать x.__len__, но это деталь реализации, которая должна оставаться скрытой от пользовательского интерфейса. - person Paulo Scardine; 22.05.2013
comment
Я попытался сформулировать ответ лучше, если вы не удовлетворены, возможно, я неправильно понял ваш вопрос. - person Paulo Scardine; 22.05.2013
comment
ваш ответ имеет смысл в том, что мне не нужно когда-либо вызывать .__format__, поэтому для этого должна быть соответствующая встроенная функция, хотя '{0}'.format тоже делает это. - person jamylak; 22.05.2013
comment
Возможно, наш BDFL удостоит нас ответом; но я не вижу лучшего объяснения, чем это. - person Burhan Khalid; 22.05.2013
comment
@PauloScardine у ​​вас есть источник цитаты из BDFL? - person Benjamin Hodgson♦; 22.05.2013
comment
Дополнительные аргументы относительно len в Часто задаваемые вопросы по дизайну и истории. Хотя это не такой полный или хороший ответ, он, бесспорно, официальный. - person abarnert; 22.05.2013
comment
Кроме того, что касается проблемы загрязнения пространства имен Ruby и JS, стоит отметить, что это неотъемлемая проблема языков с динамической типизацией. В таких разнообразных статически типизированных языках, как Haskell и C ++, бесплатные функции для конкретных типов не только возможны, но и идиоматичны. (См. Принцип Interace.) Но в языках с динамической типизацией, таких как Ruby, JS, и Python бесплатные функции должны быть универсальными. Большая часть дизайна языка / библиотеки для динамических языков - это выбор правильного набора таких функций. - person abarnert; 22.05.2013
comment
@abarnert: качественный комментарий, включенный в ответ. - person Paulo Scardine; 22.05.2013
comment
@jamylak: спасибо за отличный вопрос, это мой первый ответ, набравший 20 голосов. - person Paulo Scardine; 24.05.2013