Подтвердить что ты не робот

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

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

например.

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

по-видимому, предпочтительнее

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

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

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

4b9b3361

Ответ 1

Я думаю, что 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_code+"}").format(obj) гарантированно дает те же результаты, что и format(obj, format_code), я подозреваю, что последнее будет немного быстрее, так как не нужно разбирать строку формата, чтобы проверить любой сложный материал. Однако накладные расходы могут быть потеряны в шуме в реальной программе.

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

Ответ 2

TL;DR; 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 duck-typed подход к 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) Для некоторых операций префиксная нотация только читается лучше, чем операции postfix - prefix (и infix!), имеют давнюю традицию в математике, которая любит записи, где визуальные эффекты помогают математику думать о проблеме. Сравните легкость, с помощью которой мы переписываем формулу типа x*(a+b) в x*a + x*b к неуклюжести делать то же самое, используя необработанную нотацию OO.

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

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

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

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

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

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

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

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