2013-11-11 3 views
10

У меня есть словарь с двоеточием в ключе, которое я хочу напечатать. К сожалению, символ двоеточия используется для форматирования, поэтому мне нужно как-то избежать его.Как избежать двоеточия в формате Python() при использовании kwargs?

Например:

>>> 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' 
+1

Такая же проблема с '{'с! Восклицанием': something}' – dawg

ответ

5

В качестве временного решения:

>>> d = {'hello': 'world', 'with:colon': 'moo'} 
>>> '{hello} {}'.format(d['with:colon'],**d) 
'world moo' 
>>> '{hello} {0}'.format(d['with:colon'],**d) 
'world moo' 
+0

Да, это перешло мне в голову. :) –

10

Согласно the documentation, что вы просите, просто не представляется возможным. В частности,

Поскольку arg_name не разграниченные QUOTE, это не представляется возможным задавать произвольные словарные ключи (например, строки '10' или ':-]') в пределах строки формата.

+4

Невозможно отследить роботизированное лицо смайликов ': -]' –

2

Вы не можете - ключи должны быть синтаксически эквивалентны идентификаторам Python. См Format String Syntax в документации:

replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}" 
field_name  ::= arg_name ("." attribute_name | "[" element_index "]")* 
arg_name   ::= [identifier | integer] 
attribute_name ::= identifier 
1

Как @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' 

Очевидно, предполагается, что вы можете изменить строки формата в соответствии с требованиями. В идеале, просто измените оба конца, чтобы избежать двоеточия все вместе.

1

Жаль, что встроенный в форматировщик не позволит. Очевидным расширением синтаксиса было бы предоставление ключей, если это необходимо. Ваша строка формата будет то, как это:

format('{"with:colon"} and {hello}' 

К счастью, это, кажется, легко расширить Formatter, чтобы обеспечить этот синтаксис, вот реализация РОС:

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 
+0

+1, приятное решение - к сожалению, это делает синтаксис неудобным, но если это распространенная проблема в коде OP, это, безусловно, лучшее решение. –

+0

@Lattyware: да, возможно, побег будет приятнее, например '{with \: colon}'. – georg

1

Начиная с python 3.6, вы можете решить эту проблему с помощью новой f-струнной системы:

>>> d = {'hello': 'world', 'with:colon': 'moo'} 
>>> print(f"with:colon is equal to {d['with:colon']}") 
with:colon is equal to moo 
Смежные вопросы