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:
之后的选项仅适用于非字符串类型(例如 +
和 -
)
我想像
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:
之后的选项仅适用于非字符串类型(例如 +
和 -
)