Python defaultdict 和 lambda

100 投票
5 回答
102483 浏览
提问于 2025-04-17 07:54

在别人的代码中,我看到以下两行:

x = defaultdict(lambda: 0)
y = defaultdict(lambda: defaultdict(lambda: 0))

因为defaultdict的参数是一个默认工厂,我觉得第一行的意思是,当我用一个不存在的键k去调用x[k]时(比如像v=x[k]这样的语句),键值对(k,0)会自动添加到字典中,就好像先执行了语句x[k]=0一样。我理解得对吗?

那y又是什么呢?看起来默认工厂会创建一个默认值为0的defaultdict。但这具体意味着什么呢?我在Python的命令行里试着玩了一下,但没搞明白它到底是什么。

5 个回答

10

defaultdict 是一个特殊的字典,它在创建的时候需要一个不带参数的函数,这个函数会在找不到某个键的时候被调用,正如你所说的那样。

lambda: 0 这个函数每次调用都会返回零,但更推荐的做法是使用 defaultdict(int),这样也能达到同样的效果。

至于第二部分,作者希望在顶层字典中找不到某个键时,能够创建一个新的 defaultdict(int),或者说是一个嵌套字典。

12

你说得对,第一个部分的功能是这样的。至于 y,它会创建一个默认值为0的字典,当你查找一个不存在的键时,就会返回0。所以你可以把它想象成一个嵌套的字典。下面是一个例子:

y = defaultdict(lambda: defaultdict(lambda: 0))
print y['k1']['k2']   # 0
print dict(y['k1'])   # {'k2': 0}

如果你想创建一个和这个嵌套字典结构相同的字典,但不使用默认字典,你就需要先为 y['k1'] 创建一个内部字典,然后再把 y['k1']['k2'] 设置为0。但是使用默认字典时,当它遇到一个它没见过的键时,这些操作都是自动完成的:

y = {}
y['k1'] = {}
y['k1']['k2'] = 0

下面这个函数可以帮助你在解释器中玩一下,以便更好地理解这个概念:

def to_dict(d):
    if isinstance(d, defaultdict):
        return dict((k, to_dict(v)) for k, v in d.items())
    return d

这个函数会返回一个与嵌套的默认字典等价的普通字典,这样看起来会更容易理解,比如:

>>> y = defaultdict(lambda: defaultdict(lambda: 0))
>>> y['a']['b'] = 5
>>> y
defaultdict(<function <lambda> at 0xb7ea93e4>, {'a': defaultdict(<function <lambda> at 0xb7ea9374>, {'b': 5})})
>>> to_dict(y)
{'a': {'b': 5}}
87

我觉得第一行的意思是,当我用一个不存在的键 k 来调用 x[k] 时(比如像 v=x[k] 这样的语句),字典里会自动添加一个键值对 (k,0),就好像先执行了 x[k]=0 一样。

没错。更常见的写法是

x = defaultdict(int)

对于 y 来说,当你执行 y["ham"]["spam"] 时,如果键 "ham" 不存在,它会被插入到 y 中。与之关联的值会变成一个 defaultdict,在这个字典里,"spam" 会自动插入,并且值为 0

也就是说,y 是一种“二级”的 defaultdict。如果 "ham" 不在 y 中,那么评估 y["ham"]["spam"] 就像执行

y["ham"] = {}
y["ham"]["spam"] = 0

在普通的 dict 中一样。

撰写回答