Python 2.6 представил str.format()
метод с немного отличающимся синтаксисом от существующего %
оператора. Что лучше и для каких ситуаций?
Следующее использует каждый метод и имеет тот же результат, так в чем же разница?
#!/usr/bin/python sub1 = "python string!" sub2 = "an arg" a = "i am a %s" % sub1 b = "i am a {0}".format(sub1) c = "with %(kwarg)s!" % {'kwarg':sub2} d = "with {kwarg}!".format(kwarg=sub2) print a # "i am a python string!" print b # "i am a python string!" print c # "with an arg!" print d # "with an arg!"
Кроме того, когда происходит форматирование строки в Python? Например, если мой уровень ведения журнала установлен на ВЫСОКИЙ, я все равно получу удар для выполнения следующей
%
операции? И если так, есть ли способ избежать этого?log.debug("some debug info: %s" % some_info)
python
performance
logging
string-formatting
f-string
NorthIsUp
источник
источник
%
чаще использую старый стиль, потому что, если вам не нужны улучшенные возможностиformat()
стиля,%
стиль часто намного удобнее.format()
стиля форматирования и более старого%
стиля форматирования .Ответы:
Чтобы ответить на ваш первый вопрос ...
.format
просто кажется более сложным во многих отношениях. Раздражает%
также то, как он может принимать переменную или кортеж. Вы думаете, что всегда будет работать следующее:тем не менее, если это
name
произойдет(1, 2, 3)
, он броситTypeError
. Чтобы гарантировать, что он всегда печатает, вам нужно сделатьчто просто ужасно
.format
не имеет этих проблем. Также во втором примере, который вы привели,.format
пример выглядит намного чище.Почему бы вам не использовать его?
Чтобы ответить на ваш второй вопрос, форматирование строки происходит одновременно с любой другой операцией - когда вычисляется выражение форматирования строки. И Python, не будучи ленивым языком, вычисляет выражения перед вызовом функций, поэтому в вашем
log.debug
примере выражение"some debug info: %s"%some_info
сначала оценивается, например"some debug info: roflcopters are active"
, затем эта строка будет переданаlog.debug()
.источник
"%(a)s, %(a)s" % {'a':'test'}
log.debug("something: %s" % x)
но не наlog.debug("something: %s", x)
. Форматирование строк будет обрабатываться в методе, и вы не получите снижение производительности, если оно не будет зарегистрировано. Как всегда, Python предвидит ваши потребности =)'{0}, {0}'.format('test')
.man sprintf
и узнайте о$
нотации внутри%
заполнителейprintf("%2$d", 1, 3)
распечатать «3», это указано в POSIX, а не в C99. На самой странице справочника, на которую вы ссылались, написано: «Стандарт C99 не включает стиль, использующий« $ »…».То, что оператор по модулю (%) не может сделать, афаик:
результат
Очень полезный.
Еще один момент:
format()
будучи функцией, можно использовать в качестве аргумента в других функциях:Результаты в:
источник
map
так же легко, как и форматирование.map('some_format_string_%s'.__mod__, some_iterable)
printf("%2$s %1$s\n", "One", "Two");
скомпилированоgcc -std=c99 test.c -o test
, выводTwo One
. Но я исправлюсь: на самом деле это расширение POSIX, а не C. Я не могу найти его снова в стандарте C / C ++, где, как мне казалось, я его видел. Код работает даже с флагом 'c90'.sprintf
справочная страница . Это не перечисляет его, но позволяет библиотекам реализовать суперсет. Мой первоначальный аргумент все еще действителен, заменивC
наPosix
%
по модулю для переупорядочения заполнителей. Я все еще хотел бы не удалять этот первый комментарий для согласованности комментариев здесь. Я прошу прощения за то, что выразил свой гнев здесь. Он направлен против часто высказываемого заявления о том, что старый синтаксис сам по себе не допускает этого. Вместо того, чтобы создавать совершенно новый синтаксис, мы могли бы ввести расширения std Posix. Мы могли бы иметь оба.Предполагая, что вы используете
logging
модуль Python , вы можете передавать аргументы форматирования строки в качестве аргументов.debug()
методу, а не выполнять форматирование самостоятельно:который избегает делать форматирование, если регистратор фактически не регистрирует что-то.
источник
log.debug("some debug info: %(this)s and %(that)s", dict(this='Tom', that='Jerry'))
Однако вы не можете использовать новый.format()
синтаксис стиля здесь, даже в Python 3.3, что является позором.Начиная с Python 3.6 (2016) вы можете использовать f-строки для замены переменных:
Обратите внимание на
f"
префикс. Если вы попробуете это в Python 3.5 или более ранней версии, вы получитеSyntaxError
.См. Https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings.
источник
PEP 3101 предлагает заменить
%
оператора новым расширенным форматированием строк в Python 3, где это будет по умолчанию.источник
.format
не заменит%
форматирование строки.Но будьте осторожны, только сейчас я обнаружил один вопрос при попытке заменить все
%
с.format
в существующем коде'{}'.format(unicode_string)
будет пытаться кодировать UNICODE_STRING и, вероятно , не в состоянии .Просто посмотрите на этот интерактивный журнал сеансов Python:
s
это просто строка (называемая 'байтовым массивом' в Python3) иu
представляющая собой строку Unicode (называемая 'строкой' в Python3):Когда вы передаете объект Unicode в качестве параметра для
%
оператора, он создаст строку Unicode, даже если исходная строка не была Unicode:но
.format
функция вызовет «UnicodeEncodeError»:и он будет работать с аргументом Unicode нормально, только если исходная строка была Unicode.
или если строка аргумента может быть преобразована в строку (так называемый «байтовый массив»)
источник
format
действительно не нужны дополнительные функции нового метода ...%
интерполяция строк когда-либо исчезнет."p1=%s p2=%d" % "abc", 2
или"p1=%s p2=%s" % (tuple_p1_p2,)
. Вы можете подумать, что это ошибка кодера, но я думаю, что это просто странный ошибочный синтаксис, который выглядит хорошо для quicky-scriptie, но плохо для производственного кода.%s
,%02d
как"p1=%s p2=%02d".format("abc", 2)
. Я обвиняю тех, кто изобрел и одобрил форматирование фигурных скобок, которое требует, чтобы вы их избегали,{{}}
и выглядит ужасно imho.Еще одно преимущество
.format
(которое я не вижу в ответах): оно может принимать свойства объекта.Или в качестве ключевого аргумента:
Это не возможно с
%
, насколько я могу судить.источник
'x is {0}, y is {1}'.format(a.x, a.y)
. Следует использовать только тогда, когдаa.x
операция очень дорогая.'x is {a.x}, y is {a.y}'.format(a=a)
. Более читабельно, чем оба примера.'x is {a.x}, y is {a.y}'.format(**vars())
'{foo[bar]}'.format(foo={'bar': 'baz'})
.Your order, number {order[number]} was processed at {now:%Y-%m-%d %H:%M:%S}, will be ready at about {order[eta]:%H:%M:%S}
или что угодно. Это гораздо чище, чем пытаться предложить ту же функциональность со старым форматером. Это делает пользовательские строки формата более мощными.%
дает лучшую производительность, чемformat
из моего теста.Тестовый код:
Python 2.7.2:
Результат:
Python 3.5.2
Результат
Это выглядит в Python2, разница невелика, тогда как в Python3,
%
намного быстрее, чемformat
.Спасибо @Chris Cogdon за пример кода.
Изменить 1:
Снова протестирован на Python 3.7.2 в июле 2019 года.
Результат:
Там нет большой разницы. Я думаю, что Python постепенно улучшается.
Изменить 2:
После того, как кто-то упомянул в комментарии f-строку Python 3, я провел тест для следующего кода в Python 3.7.2:
Результат:
Кажется, f-струна все еще медленнее чем,
%
но лучше чемformat
.источник
str.format
дает больше функциональных возможностей (особенно, например, специализированное форматирование'{0:%Y-%m-%d}'.format(datetime.datetime.utcnow())
). Производительность не может быть абсолютным требованием всех рабочих мест. Используйте правильный инструмент для работы.%
оператор позволяет повторно использоватьprintf
знания; Словарная интерполяция является очень простым расширением принципа.Как я обнаружил сегодня, старый способ форматирования строк через
%
не поддерживаетDecimal
, модуль Python для десятичной фиксированной запятой и арифметики с плавающей запятой, из коробки.Пример (с использованием Python 3.3.5):
Вывод:
Конечно, могут быть обходные пути, но вы все равно можете рассмотреть возможность использования
format()
метода прямо сейчас.источник
str(d)
перед расширением параметра, тогда как форматирование в старом стиле, вероятно, вызываетfloat(d)
первым.str(d)
вернулись"3.12375239e-24"
, а не"0.00000000000000000000000312375239000000000000000000"
Если ваш python> = 3.6, отформатированный в F-string литерал - ваш новый друг.
Это более просто, чисто и лучше.
источник
Как примечание, вам не нужно снижать производительность, чтобы использовать новый стиль форматирования с ведением журнала. Вы можете передать любой объект
logging.debug
,logging.info
и т.д. , который реализует__str__
метод волшебной. Когда модуль протоколирования решил, что он должен выдать объект сообщения (каким бы он ни был), он вызываетstr(message_object)
перед этим. Таким образом, вы можете сделать что-то вроде этого:Все это описано в документации по Python 3 ( https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles ). Тем не менее, он будет работать и с Python 2.6 ( https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages ).
Одним из преимуществ использования этого метода, помимо того факта, что он не зависит от стиля форматирования, является то, что он допускает ленивые значения, например, функцию
expensive_func
выше. Это обеспечивает более элегантную альтернативу советам, которые даются в документации по Python здесь: https://docs.python.org/2.6/library/logging.html#optimization .источник
format
без снижения производительности - делает это, переопределяя__str__
точно так, какlogging
было предназначено - сокращает вызов функции до одной буквы (N
), которая очень похожа на некоторые стандартные способы определения строк - И допускает ленивый вызов функции. Спасибо! +1logging.Formatter(style='{')
параметра?%
Может помочь ситуация, когда вы форматируете выражения регулярных выражений. Например,поднимает
IndexError
. В этой ситуации вы можете использовать:Это позволяет избежать записи регулярного выражения как
'{type_names} [a-z]{{2}}'
. Это может быть полезно, когда у вас есть два регулярных выражения, где один используется один без формата, но объединение обоих форматируется.источник
'{type_names} [a-z]{{2}}'.format(type_names='triangle|square')
. Это как сказать,.format()
может помочь при использовании строк, которые уже содержат символ процента. Конечно. Вы должны избежать их тогда."One situation where % may help is when you are formatting regex expressions."
Конкретно, предположим, чтоa=r"[a-z]{2}"
это кусок регулярного выражения, который вы будете использовать в двух разных конечных выражениях (например,c1 = b + a
иc2 = a
). Предположим, чтоc1
необходимоformat
редактировать (например,b
нужно отформатировать время выполнения), ноc2
это не так. Тогда вам нужноa=r"[a-z]{2}"
дляc2
иa=r"[a-z]{{2}}"
дляc1.format(...)
.Я хотел бы добавить, что начиная с версии 3.6, мы можем использовать fstrings, как показано ниже
Которые дают
Все преобразуется в строки
Результат:
Вы можете передать функцию, как в методе других форматов
Давать например
источник
Для версии Python> = 3.6 (см. PEP 498 )
источник
Python 3.6.7 сравнительный:
Вывод:
источник
Но одна вещь заключается в том, что, если у вас есть вложенные фигурные скобки, не будет работать для формата, но
%
будет работать.Пример:
источник