首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >string.Formatter抛出KeyError '‘

string.Formatter抛出KeyError '‘
EN

Stack Overflow用户
提问于 2015-09-08 12:19:45
回答 1查看 1K关注 0票数 4

我想打印出像key+value一样的this question

代码语言:javascript
运行
复制
key a:         1
key ab:        2
key abc:       3
       ^ this colon is what I want

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

代码语言:javascript
运行
复制
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))

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

KeyError:'‘在Python2.7和3.4中。如果我取消注释for循环以查看错误中发生了什么,但是最后的print语句将只显示一个换行符。

当我做最后一行时:

代码语言:javascript
运行
复制
print('key {:<{}} {}'.format(k, w, v))

这起作用(键后有空格),当我这样做时:

代码语言:javascript
运行
复制
print('key {::<{}} {}'.format(k, w, v))

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

我为什么要拿到KeyError?我如何调试这个?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-09-08 12:46:01

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

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

您可以通过子类MyFormatter来模拟新行为。

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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))

并得到:

代码语言:javascript
运行
复制
key a:         1
key ab:        2
key abc:       3

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

Python格式化例程实际上非常聪明,可以让您像宽度格式一样在字符串中插入尾随字符:

代码语言:javascript
运行
复制
    print(kf.format('key {:t{}<{}} {}', k, ':', w, v))

提供相同的结果,并允许您动态更改“:

您还可以将format_field更改为:

代码语言:javascript
运行
复制
    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)

并提交任何类型的:

代码语言:javascript
运行
复制
print(kf.format('key {:t{}<{}} {}', (1, 2), '@', 10, 3))

得到:

代码语言:javascript
运行
复制
key (1, 2)@    3

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32457680

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档