Python defaultdict和lambda

98

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

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 shell中尝试了一下,但无法弄清楚它到底是什么。
5个回答

86
我认为第一行的意思是,当我调用一个不存在的键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 来说。


6
使用functools模块中的partial函数,可以创建类似于defaultdict的'y',而不需要使用lambda表达式。示例代码如下:y = defaultdict(partial(defaultdict, int)) - Lauritz V. Thaulow
1
快速跟进:为什么defaultdict(int)lambda: 0的工作方式相同?换句话说,为什么defaultdict(int)总是返回0作为值? - briandk
6
因为int()会返回零。 - Fred Foo

12

对于第一个代码片段,你是正确的。至于y,它会在键不存在于y时创建一个默认值为0的defaultdict,因此你可以将其视为嵌套字典。考虑以下示例:

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

如果不使用defaultdict创建等效的嵌套字典结构,则需要为y ['k1']创建一个内部字典,然后将y ['k1'] ['k2']设置为0,但是当defaultdict遇到它没有见过的键时,它在幕后完成所有这些操作:

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

这将返回嵌套的defaultdict的字典等效形式,更容易阅读,例如:

>>> 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}}

10

defaultdict需要一个零参数可调用对象作为其构造函数,在找不到键时调用该对象,就像您所解释的那样。

lambda: 0当然总是返回零,但首选的方法是defaultdict(int),它将完成相同的操作。

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


4
在这种情况下,使用 int 更易读。使用 int 可能也会稍微更快,但主要原因是它会使代码更加清晰明了。 - Kenan Banks
3
通过docs.python.org:函数int()总是返回零,它只是常量函数的一种特殊情况。创建常量函数的更快、更灵活的方法是使用itertools.repeat(),它可以提供任何常量值(不仅仅是零)。然后展示了一个itertools.repeat()的示例,这相当不错。我建议阅读:http://docs.python.org/2/library/collections.html#defaultdict-objects - Dmitry Minkovsky

5

所有答案都够好,但我想补充一些信息:

"defaultdict需要一个可调用的参数。该可调用对象返回的结果是字典在尝试访问不存在的键时返回的默认值。"

以下是一个例子:

SAMPLE= {'Age':28, 'Salary':2000}
SAMPLE = defaultdict(lambda:0,SAMPLE)

>>> SAMPLE
defaultdict(<function <lambda> at 0x0000000002BF7C88>, {'Salary': 2000, 'Age': 28})

>>> SAMPLE['Age']----> This will return 28
>>> SAMPLE['Phone']----> This will return 0   # you got 0 as output for a non existing key inside SAMPLE

3

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

如果你尝试使用这个代码:y['a']['b'] += 1,会很有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接