string.Formatter 抛出 KeyError ''

string.Formatter throws KeyError ''

我想像

那样打印键值对
key a:         1
key ab:        2
key abc:       3
       ^ this colon is what I want

但我不喜欢那里的答案,我尝试像这样子类化 string.Formatter

from __future__ import print_function

from string import Formatter

class KeyFormatter(Formatter):
    def parse(self, fmtstr):
        res = super(KeyFormatter, self).parse(fmtstr)
        #for r in res:
        #    print(r)
        return res

kf = KeyFormatter()
w = 10

x = dict(a=1, ab=2, abc=3)

for k in sorted(x):
    v = x[k]
    print(kf.format('key {::<{}} {}', k, w, v))

我想调试解析以查看是否可以获取格式字符串中插入的额外“:”,但这会引发

按键错误:'' 在 Python 2.7 和 3.4 中。如果我取消注释 for 循环以查看发生了什么,错误就会消失,但最终的打印语句只会显示一个换行符。

当我写最后一行时:

print('key {:<{}} {}'.format(k, w, v))

这有效(键后有空格),当我这样做时:

print('key {::<{}} {}'.format(k, w, v))

我得到多个“:”而不是空格。但是没有KeyError。

为什么我得到 KeyError?我该如何调试?

这里有两个有点相关的问题,如何调试的简单答案是:你不能,至少不能使用 print 语句,或者任何本身使用字符串格式的东西,因为这会在另一种字符串格式期间发生并破坏格式化程序的状态。

它抛出错误是因为 string.Formatter() 不支持空字段,这是对从 2.6 到 3.1(和 2.7)的格式的补充,在 C代码,但未反映在 string 模块中。

您可以通过 class 子 class MyFormatter:

来模拟新行为
from __future__ import print_function

from string import Formatter
import sys

w = 10
x = dict(a=1, ab=2, abc=3)

if sys.version_info < (3,):
    int_type = (int, long)
else:
    int_type = (int)    

class MyFormatter(Formatter):

    def vformat(self, *args):
        self._automatic = None
        return super(MyFormatter, self).vformat(*args)

    def get_value(self, key, args, kwargs):
        if key == '':
            if self._automatic is None:
                self._automatic = 0
            elif self._automatic == -1:
                raise ValueError("cannot switch from manual field specification "
                                 "to automatic field numbering")
            key = self._automatic
            self._automatic += 1
        elif isinstance(key, int_type):
            if self._automatic is None:
                self._automatic = -1
            elif self._automatic != -1:
                raise ValueError("cannot switch from automatic field numbering "
                                 "to manual field specification")
        return super(MyFormatter, self).get_value(key, args, kwargs)

应该去掉 KeyError。之后你应该覆盖方法 format_field 而不是 parse:

if sys.version_info < (3,):
    string_type = basestring
else:
    string_type = str

class TrailingFormatter(MyFormatter):
    def format_field(self, value, spec):
        if isinstance(value, string_type) and len(spec) > 1 and spec[0] == 't':
            value += spec[1]  # append the extra character
            spec = spec[2:]
        return super(TrailingFormatter, self).format_field(value, spec)

kf = TrailingFormatter()
w = 10

for k in sorted(x):
    v = x[k]
    print(kf.format('key {:t:<{}} {}', k, w, v))

并得到:

key a:         1
key ab:        2
key abc:       3

注意在格式字符串中引入尾随字符的格式说明符 (t)。

Python 格式化例程实际上足够智能,可以让您在字符串中插入尾随字符,就像宽度格式化一样:

    print(kf.format('key {:t{}<{}} {}', k, ':', w, v))

给出相同的结果并让您动态更改“:

您还可以将 format_field 更改为:

    def format_field(self, value, spec):
        if len(spec) > 1 and spec[0] == 't':
            value = str(value) + spec[1]  # append the extra character
            spec = spec[2:]
        return super(TrailingFormatter, self).format_field(value, spec)

并提交任何类型:

print(kf.format('key {:t{}<{}} {}', (1, 2), '@', 10, 3))

获得:

key (1, 2)@    3

但是由于在将值传递给 Formatter.formatfield() 之前将值转换为字符串,如果 str(val) 得到的值与使用 {0}.format(val) 的值不同,则可能会得到不同的结果 and/or 在 t: 之后的选项仅适用于非字符串类型(例如 +-