Ответ 1
В качестве обходного пути:
>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> '{hello} {}'.format(d['with:colon'],**d)
'world moo'
>>> '{hello} {0}'.format(d['with:colon'],**d)
'world moo'
У меня есть словарь с двоеточием в ключе, которое я хочу напечатать. К сожалению, символ двоеточия используется для форматирования, поэтому мне нужно как-то избежать его.
Например:
>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> '{hello}'.format(**d)
'world'
>>> '{with:colon}'.format(**d)
KeyError: 'with'
>>> '{with\:colon}'.format(**d)
KeyError: 'with\\'
>>> '{with::colon}'.format(**d)
KeyError: 'with'
В качестве обходного пути:
>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> '{hello} {}'.format(d['with:colon'],**d)
'world moo'
>>> '{hello} {0}'.format(d['with:colon'],**d)
'world moo'
Согласно документации, то, что вы просите, просто невозможно. В частности,
Поскольку arg_name не разделяется запятыми, невозможно указать произвольные словарные ключи (например, строки
'10'
или':-]'
) в строке формата.
Вы не можете - ключи должны быть синтаксически эквивалентны идентификаторам Python. См. Формат строкового синтаксиса в документации:
replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name ::= arg_name ("." attribute_name | "[" element_index "]")*
arg_name ::= [identifier | integer]
attribute_name ::= identifier
Как @murgatroid99 указывает в его ответе, это невозможно.
Взаимодействие будет заключаться в замене ключей на действующие ключи:
d_sanitised = {key.replace(":", "-"): value for key, value in d.items()}
Естественно, вы можете быть осторожны, если есть вероятность конфликтов с другими ключами.
>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> d_sanitised = {key.replace(":", "-"): value for key, value in d.items()}
>>> '{with-colon}'.format(**d_sanitised)
'moo'
Очевидно, это предполагает, что вы можете изменить строки формата, чтобы они соответствовали. В идеале просто измените оба конца, чтобы избежать двоеточия.
Жаль, что встроенный форматтер этого не позволяет. Очевидным расширением синтаксиса было бы предоставление ключей, если это необходимо. Ваша строка формата будет выглядеть следующим образом:
format('{"with:colon"} and {hello}'
К счастью, оказалось, что легко расширить Formatter для обеспечения этого синтаксиса, здесь реализация POC:
class QuotableFormatter(string.Formatter):
def __init__(self):
self.super = super(QuotableFormatter, self)
self.super.__init__()
self.quotes = {}
def parse(self, format_string):
fs = ''
for p in re.findall(r'(?:".+?")|(?:[^"]+)', format_string):
if p[0] == '"':
key = '_q_' + str(len(self.quotes))
self.quotes[key] = p[1:-1]
fs += key
else:
fs += p
return self.super.parse(fs)
def get_field(self, field_name, args, kwargs):
if field_name.startswith('_q_'):
field_name = self.quotes[field_name]
return self.super.get_field(field_name, args, kwargs)
Использование:
d = {'hello': 'world', 'with:colon': 'moo', "weird!r:~^20": 'hi'}
print QuotableFormatter().format('{"with:colon":*>20} and {hello} and {"weird!r:~^20"}', **d)
# *****************moo and world and hi
Как и в случае с python 3.6, вы можете решить это с помощью нового f-string formating:
>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> print(f"with:colon is equal to {d['with:colon']}")
with:colon is equal to moo