使用kwargs时如何以Python格式()转义冒号?

时间:2013-11-11 18:43:50

标签: python string-formatting

我想要打印一个带有冒号的字典。不幸的是冒号字符用于格式化,所以我需要以某种方式逃避它。

例如:

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

6 个答案:

答案 0 :(得分:10)

根据the documentation,你要问的是根本不可能的。具体地,

  

由于arg_name不是引号分隔的,因此无法在格式字符串中指定任意字典键(例如,字符串'10'':-]')。

答案 1 :(得分:6)

作为解决方法:

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

答案 2 :(得分: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

答案 3 :(得分:2)

从python 3.6开始,您可以使用新的f-string格式化来解决这个问题:

>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> print(f"with:colon is equal to {d['with:colon']}")
with:colon is equal to moo

答案 4 :(得分: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'

显然,这假设您可以修改格式字符串以适应。理想情况下,只需修改两端即可避免冒号。

答案 5 :(得分:1)

遗憾的是,内置格式化程序不允许这样做。一个明显的语法扩展是允许在必要时引用键。您的格式字符串将如下所示:

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