使用关键字解包格式化defaultdict
我想用关键字解包操作符 **
来格式化并打印字典中的数据。
格式字符串可能会涉及很多关键字,而字典里可能没有所有需要的键。对于缺失的键,我希望用字符串 'N/A' 作为默认值。
我想要一个聪明的解决方案来处理这个默认值的问题,可能可以使用 defaultdict
。
这里是一个使用普通 dict
的初步解决方案。
# Cumbersome solution with dict
format_str = '{date} {version} {comment}'
data = dict()
data['date'] = 'today'
data['version'] = 'v1'
data['comment'] = 'N/A' # I want to avoid this
print format_str.format(**data)
# prints: today v1 N/A
我希望避免为缺失的键显式地赋值 'N/A'。
下面的解决方案同样使用普通的 dict
,并分析格式字符串来构建关键字列表:
# Another solutions with handmade defaults for missing keys
format_str = '{date} {version} {comment}'
data = dict()
data['date'] = 'today'
data['version'] = 'v1'
import re
for k in re.findall('{(\w+)}', format_str):
if k not in data:
data[k] = 'N/A'
print format_str.format(**data)
# prints: today v1 N/A
这个使用 re.findall
的解决方案并不是特别优雅或稳健,因为格式字符串的语法比上面的 {(\w+)}
要复杂得多。
下面的解决方案本来是我最喜欢的……如果它没有因为一个明显的原因而失败。
# Failed attempt with defaultdict
from collections import defaultdict
format_str = '{date} {version} {comment}'
data = defaultdict(lambda x:'N/A')
data['date'] = 'today'
data['version'] = 'v1'
print format_str.format(**data)
# raises KeyError: 'comment'
这里的问题是 **
实际上是解包 data
中的关键字,所以 format
并不会在 data
中查找请求的关键字,因此没有给 data
提供默认值的机会。
有没有解决这个问题的方法?比如有没有一个替代的 format
函数,可以实际调用 data.get(kwd)
,从而获取 N/A
的值?
2 个回答
-1
已经有一个很好的解决方案使用了格式化工具。
不过在这种情况下,你并没有利用到关键字解包的好处。你必须在格式字符串中指定你想打印的键。
format_str = '{date} {version} {comment}'
而字典本身就已经保持了关键字和对应值的关系。
所以对于这样的字典
>>> d
{'version': 'v1', 'date': 'today'}
使用默认值来调用 dict.get() 方法。
>>> print '{} {} {}'.format(d['date'],d['version'],d.get('comment','n/a'))
today v1 n/a
如果你想把关键字管理集中在一个地方(就像你在格式字符串中做的那样),我会尝试这样的方式
>>> f=lambda x: (x.get('date'),x.get('version'),x.get('comment','N/A'))
>>> print '{} {} {}'.format(*f(d))
today v1 N/A
或者这样
>>> f=lambda x: '{} {} {}'.format(x['date'],x['version'],x.get('comment','N/A'))
>>> print f(d)
today v1 N/A
这样做的好处是,减少了导入的内容。
3
使用 string.Formatter.vformat()
方法,并把 defaultdict
传递给它。
from collections import defaultdict
from string import Formatter
fmtr = Formatter()
format_str = '{date} {version} {comment}'
data = defaultdict(lambda: 'N/A')
data['date'] = 'today'
data['version'] = 'v1'
print fmtr.vformat(format_str, (), data)