Можно ли выполнить частичное форматирование строки с помощью расширенных методов форматирования строки, аналогичных safe_substitute()
функции шаблона строки ?
Например:
s = '{foo} {bar}'
s.format(foo='FOO') #Problem: raises KeyError 'bar'
python
string-formatting
P3trus
источник
источник
{bar:1.2f}
__missing__()
, верните экземпляр переопределенного настраиваемого класса__format__()
таким образом, чтобы вернуть исходный заполнитель, включая спецификацию формата. Подтверждение концепции: ideone.com/xykV7RЕсли вы знаете, в каком порядке форматируете:
Используйте это так:
Нельзя указывать
foo
иbar
одновременно - надо делать это последовательно.источник
s.format(foo='FOO',bar='BAR')
тогда я все равно получу'FOO {bar}'
, несмотря ни на что. Не могли бы вы прояснить это?Вы можете использовать короткую, наиболее читаемую
partial
функцию,functools
которая также описывает намерение кодера:источник
python from functool import partial s = "{foo} {bar}".format s_foo = partial(s, foo="FOO") print(s_foo(bar="BAR")) # FOO BAR print(s(foo="FOO", bar="BAR")) # FOO BAR
partial()
не поможет мне, если мне нужно будет обработать частично отформатированную строку (то есть"FOO {bar}"
)."{foo} {{bar}}".format(foo="{bar}").format(bar="123")
из других примеров. Я ожидал,"{bar} 123"
но они выходят"123 123"
.Это ограничение
.format()
- невозможность делать частичные замены - меня беспокоит.После оценки написания настраиваемого
Formatter
класса, как описано во многих ответах здесь, и даже при рассмотрении использования сторонних пакетов, таких как lazy_format , я обнаружил гораздо более простое встроенное решение: строки шаблонаОн предоставляет аналогичные функции, но также обеспечивает
safe_substitute()
метод частичной замены . Строки шаблона должны иметь$
префикс (что кажется немного странным, но общее решение, я думаю, лучше).На основе этого сформирована удобная обертка:
Точно так же оболочка, основанная на ответе Свена, который использует форматирование строки по умолчанию:
источник
Не уверен, что это нормально в качестве быстрого решения, но как насчет
? :)
источник
Если вы определите свой собственный,
Formatter
который переопределяетget_value
метод, вы можете использовать его для сопоставления неопределенных имен полей с тем, что вам нужно:http://docs.python.org/library/string.html#string.Formatter.get_value
Например, вы могли бы карту ,
bar
чтобы"{bar}"
еслиbar
не в kwargs.Однако для этого необходимо использовать
format()
метод вашего объекта Formatter, а не строковыйformat()
метод.источник
Попробуйте это.
источник
{{
и}}
является способом экранирования меток форматирования, поэтомуformat()
не выполняет подстановку и заменяет{{
и}}
на{
и}
, соответственно.{{ }}
формат работает только для одного формата, если вам нужно применить больше, вам нужно будет добавить больше{}
. ех.'fd:{uid}:{{topic_id}}'.format(uid=123).format(a=1)
вернет ошибку, поскольку второй формат не предоставляетtopic_id
значение.Благодаря комментарию Эмбер я придумал следующее:
источник
{field!s: >4}
становится{field}
Для меня этого было достаточно:
источник
Все найденные мной решения, похоже, имели проблемы с более продвинутыми спецификациями или вариантами преобразования. @SvenMarnach FormatPlaceholder на удивление умен, но он не работает должным образом с принуждением (например
{a!s:>2s}
), потому что он вызывает__str__
вместо метод (в этом примере),__format__
и вы теряете любое дополнительное форматирование.Вот что у меня получилось и некоторые из его ключевых особенностей:
str.format
(не только отображение){k!s}
{!r}
{k:>{size}}
{k.foo}
{k[0]}
{k!s:>{size}}
Я обнаружил проблемы с различными реализациями после того, как написал несколько тестов о том, как должен вести себя этот метод. Они внизу, если кто-то сочтет их проницательными.
источник
Мое предложение было бы следующим (протестировано с Python3.6):
Обновление: здесь показан еще более элегантный способ (создание подклассов
dict
и перегрузка__missing__(self, key)
): https://stackoverflow.com/a/17215533/333403источник
Предполагая, что вы не будете использовать строку, пока она полностью не заполнится, вы можете сделать что-то вроде этого класса:
Пример:
источник
Есть еще один способ добиться этого, т. Е. Использовать
format
и%
заменять переменные. Например:источник
Очень уродливое, но самое простое решение для меня - просто сделать:
Таким образом, вы по-прежнему можете использовать его
tmpl
как обычный шаблон и выполнять частичное форматирование только при необходимости. Я считаю эту проблему слишком тривиальной, чтобы использовать излишнее решение вроде Мохана Раджа.источник
После тестирования наиболее перспективные решения от здесь и там , я понял , что ни один из них действительно отвечают следующим требованиям:
str.format_map()
шаблоном;Итак, я написал собственное решение, удовлетворяющее указанным выше требованиям. ( РЕДАКТИРОВАТЬ : теперь версия @SvenMarnach - как указано в этом ответе - похоже, обрабатывает угловые случаи, которые мне нужны).
По сути, я закончил тем, что проанализировал строку шаблона, нашел соответствующие вложенные
{.*?}
группы (с помощьюfind_all()
вспомогательной функции) и построил форматированную строку постепенно и напрямую, используяstr.format_map()
при этом любой потенциалKeyError
.(Этот код также доступен в FlyingCircus - ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: я являюсь его основным автором.)
Использование этого кода будет следующим:
Давайте сравним это с моим любимым решением (от @SvenMarnach, который любезно поделился своим кодом тут и там ):
Вот пара тестов:
и код для его запуска:
в результате чего:
Как видите, обновленная версия теперь, кажется, хорошо справляется с крайними случаями, когда предыдущая версия терпела неудачу.
По времени они находятся в пределах прибл. 50% друг от друга, в зависимости от фактического
text
форматирования (и, вероятно, фактическогоsource
), но,safe_format_map()
похоже, имеют преимущество в большинстве выполненных мною тестов (что бы они ни значили, конечно):источник
{d[x]}
насколько мне известно , это недопустимая строка формата.field_name ::= arg_name ("." attribute_name | "[" element_index "]")*
и какstr.format()
иstr.format_map()
понять его. Я бы сказал, что есть достаточно доказательств того, что это допустимая строка формата.str.format()
с нецелым индексом в квадратных скобках? Я могу заставить работать только целочисленные индексы.a = dict(b='YAY!'); '{a[b]}'.format_map(dict(a=a))
понимает: «УРА!»a[b]
в коде Python, но на самом деле этоa["b"]
спасибо!Если вы хотите распаковать словарь для передачи аргументов
format
, как в этом связанном вопросе , вы можете использовать следующий метод.Сначала предположим, что строка
s
такая же, как в этом вопросе:и значения даны в следующем словаре:
Ясно, что это не сработает:
Однако вы можете сначала получить
set
из всех именованных аргументовs
и создать словарь, который отображает аргумент на себя, заключенный в фигурные скобки:Теперь воспользуйтесь
args
словарем, чтобы заполнить недостающие ключиreplacements
. Для python 3.5+ это можно сделать одним выражением :Для более старых версий python вы можете позвонить
update
:источник
Мне нравится ответ @ sven-marnach. Мой ответ - это просто его расширенная версия. Он допускает форматирование без ключевых слов и игнорирует лишние ключи. Вот примеры использования (имя функции является ссылкой на форматирование f-строки Python 3.6):
А вот мой код:
источник
Если вы делаете много шаблонов и обнаруживаете, что встроенные в Python функциональные возможности шаблонов строк недостаточны или неуклюжи, посмотрите на Jinja2 .
Из документов:
источник
Прочитав комментарий @Sam Bourne, я изменил код @SvenMarnach, чтобы он работал правильно с принуждением (например,
{a!s:>2s}
) без написания собственного парсера. Основная идея состоит не в преобразовании в строки, а в объединении недостающих ключей с тегами приведения.Используйте (например) вот так
Следующие тесты (на основе тестов @ norok2) проверяют вывод на предмет традиционности
format_map
и наsafe_format_map
основе класса выше в двух случаях: с правильными ключевыми словами или без них.Какие выходы
источник
Вы можете обернуть его функцией, которая принимает аргументы по умолчанию:
источник