string.Formatter抛出KeyError''

时间:2015-09-08 12:19:45

标签: python string-formatting

我想打印出this question

中的键+值对
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))

我想调试解析,看看我是否可以获得额外的&#39; :&#39;插入格式字符串,但这会抛出一个

KeyError:&#39;&#39; 在Python 2.7和3.4中。如果我取消注释for循环以查看错误中的内容消失,但最终的print语句只显示换行符。

当我做最后一行时:

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

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

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

我得到了多个&#39;:&#39;而不是空格。但没有KeyError。

为什么我得到KeyError?我该怎么调试呢?

1 个答案:

答案 0 :(得分:0)

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

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

您可以通过继承类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)和/或使用t:不同的值,则可能会获得不同的结果+后仅适用于非字符串类型的选项(例如-<GTD> <BLOCK> <G_47_1_1>1010</G_47_1_1> <G_47_1_2>6680520.46</G_47_1_2> <G_47_1_3>15000R</G_47_1_3> <G_47_1_4>15000.00</G_47_1_4> <G_47_1_5>PER</G_47_1_5> <G_47_2_1>5010</G_47_2_1> <G_47_2_2>86723.30</G_47_2_2> <G_47_2_3>18%</G_47_2_3> <G_47_2_4>15610.19</G_47_2_4> <G_47_2_5>RTY</G_47_2_5> <G_47_3_1>3010</G_47_2_1> <G_47_4_2>86723.30</G_47_2_2> <G_47_5_3>18%</G_47_2_3> <G_47_6_4>15610.19</G_47_2_4> <G_47_7_5>GH</G_47_2_5> </BLOCK> <BLOCK> ... </BLOCK> <GTD>