如果我用Python编写:
data = {'n': 3, 'k': 3.141594, 'p': {'a': 7, 'b': 8}}
print('{n}, {k:.2f}, {p[a]}, {p[b]}'.format(**data))
del data['k']
data['p']['b'] = None
print('{n}, {k:.2f}, {p[a]}, {p[b]}'.format(**data))
我明白了:
3, 3.14, 7, 8
Traceback (most recent call last):
File "./funky.py", line 186, in <module>
print('{n}, {k:.2f}, {p[a]}, {p[b]}'.format(**data))
KeyError: 'k'
而不是错误消息如何让Python更优雅地格式化None和不存在的字段?
举一个例子,我想在输出中看到更像是:
3, 3.14, 7, 8
3, ~, 7, ~
当然,理想情况下,我希望能够指定使用的字符串而不是那些缺失的值。
答案 0 :(得分:34)
import string
class PartialFormatter(string.Formatter):
def __init__(self, missing='~~', bad_fmt='!!'):
self.missing, self.bad_fmt=missing, bad_fmt
def get_field(self, field_name, args, kwargs):
# Handle a key not found
try:
val=super(PartialFormatter, self).get_field(field_name, args, kwargs)
# Python 3, 'super().get_field(field_name, args, kwargs)' works
except (KeyError, AttributeError):
val=None,field_name
return val
def format_field(self, value, spec):
# handle an invalid format
if value==None: return self.missing
try:
return super(PartialFormatter, self).format_field(value, spec)
except ValueError:
if self.bad_fmt is not None: return self.bad_fmt
else: raise
fmt=PartialFormatter()
data = {'n': 3, 'k': 3.141594, 'p': {'a': '7', 'b': 8}}
print(fmt.format('{n}, {k:.2f}, {p[a]}, {p[b]}', **data))
# 3, 3.14, 7, 8
del data['k']
data['p']['b'] = None
print(fmt.format('{n}, {k:.2f}, {p[a]:.2f}, {p[b]}', **data))
# 3, ~~, !!, ~~
设置完成后,如果找不到字段或属性,则会打印~~
;如果在给定字段值时使用了无效格式,则会打印!!
。 (如果你想要提出一个值错误的默认值,只需使用None
作为关键字参数bad_fmt
。)
要处理丢失的密钥,您需要将get_field
子类化为捕获KeyError
或AttributeError
和format_field
以返回缺失密钥的默认值。
由于您正在捕获format_field
错误,因此您可以通过从超类中捕获ValueError
来捕获错误的格式字段。
答案 1 :(得分:8)
str.format()
方法没有为您提供处理缺失键或替换值的直接方法。
你可以添加一个间接层;传递处理缺失和None
值的映射,并改变格式以仅使用该参数:
class PlaceholderFormatValue():
def __format__(self, spec):
return '~'
def __getitem__(self, name):
# handle further nested item access
return self
class formatting_dict(dict):
def __getitem__(self, name):
value = self.get(name)
if isinstance(value, dict):
# rewrap nested dictionaries to handle missing nested keys
value = type(self)(value)
return value if value is not None else PlaceholderFormatValue()
print('{0[n]}, {0[k]:.2f}, {0[p][a]}, {0[p][b]}'.format(formatting_dict(data)))
现在所有的插槽都引用位置参数0
,它被视为字典,但是键查找总是成功,并且缺少的值和None
都被占位符值替换。
此处PlaceholderFormatValue()
确保无论格式规范给出什么,都可以将值插入到格式中。这使{0[k]:.2f}
工作,例如。
通过包装任何dict
值并具有PlaceholderFormatValue
句柄项访问权限,上面也可以处理无法提供嵌套键或整个词典:
>>> data = {'n': 3, 'k': 3.141594, 'p': {'a': 7, 'b': 8}}
>>> del data['k']
>>> data['p']['b'] = None
>>> print('{0[n]}, {0[k]:.2f}, {0[p][a]}, {0[p][b]}'.format(formatting_dict(data)))
3, ~, 7, ~
>>> del data['p']['a']
>>> print('{0[n]}, {0[k]:.2f}, {0[p][a]}, {0[p][b]}'.format(formatting_dict(data)))
3, ~, ~, ~
>>> del data['p']
>>> print('{0[n]}, {0[k]:.2f}, {0[p][a]}, {0[p][b]}'.format(formatting_dict(data)))
3, ~, ~, ~
答案 2 :(得分:5)
如果您能够单独进行格式化,则可以使用Template.safe_substitute
优雅地处理缺失值:
>>> from string import Template
>>> t = Template("$a $b $c")
>>> t.safe_substitute(a=3)
'3 $b $c'