使用关键字解包格式化defaultdict

3 投票
2 回答
1836 浏览
提问于 2025-04-17 21:16

我想用关键字解包操作符 ** 来格式化并打印字典中的数据。

格式字符串可能会涉及很多关键字,而字典里可能没有所有需要的键。对于缺失的键,我希望用字符串 '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)

撰写回答