Python defaultdict的defaultdict?

Python defaultdict的defaultdict?,python,collections,Python,Collections,有没有办法使用defaultdict(defaultdict(int))使下面的代码正常工作 for x in stuff: d[x.a][x.b] += x.c_int d需要特别构建,具体取决于x.a和x.b元素 我可以使用: for x in stuff: d[x.a,x.b] += x.c_int 但这样我就不能使用: d.keys() d[x.a].keys() 是的,像这样: defaultdict(lambda: defaultdict(int)) 尝试访问

有没有办法使用
defaultdict(defaultdict(int))
使下面的代码正常工作

for x in stuff:
    d[x.a][x.b] += x.c_int
d
需要特别构建,具体取决于
x.a
x.b
元素

我可以使用:

for x in stuff:
    d[x.a,x.b] += x.c_int
但这样我就不能使用:

d.keys()
d[x.a].keys()
是的,像这样:

defaultdict(lambda: defaultdict(int))
尝试访问不存在的密钥时,将调用
defaultdict
(本例中为
lambda:defaultdict(int)
)的参数。它的返回值将被设置为该键的新值,这意味着在本例中,
d[键不存在]
的值将是
defaultdict(int)


如果尝试从最后一个defaultdict访问一个键,即
d[key\u doesn\u exist][key\u doesn\u exist]
它将返回0,这是最后一个defaultdict的参数的返回值,即
int()

defaultdict构造函数的参数是为构建新元素而调用的函数。所以让我们用一个lambda

>>> from collections import defaultdict
>>> d = defaultdict(lambda : defaultdict(int))
>>> print d[0]
defaultdict(<type 'int'>, {})
>>> print d[0]["x"]
0
一些额外功能

>>> c.most_common()[:2]
[('and thank you', 42), ('goodbye', 1)]

有关更多信息,请参见和

我发现使用
部分
稍微优雅一些:

import functools
dd_int = functools.partial(defaultdict, int)
defaultdict(dd_int)

当然,这与lambda相同。

其他人正确回答了您的问题,即如何使以下各项发挥作用:

for x in stuff:
    d[x.a][x.b] += x.c_int
另一种方法是对键使用元组:

d = defaultdict(int)
for x in stuff:
    d[x.a,x.b] += x.c_int
    # ^^^^^^^ tuple key

这种方法的优点在于它简单且易于扩展。如果需要三层深度的映射,只需使用三项元组作为键。

作为参考,可以通过以下方式实现通用嵌套的
defaultdict
工厂方法:

from collections import defaultdict
from functools import partial
from itertools import repeat


def nested_defaultdict(default_factory, depth=1):
    result = partial(defaultdict, default_factory)
    for _ in repeat(None, depth - 1):
        result = partial(defaultdict, result)
    return result()
深度定义了使用
default\u factory
中定义的类型之前嵌套字典的数量。 例如:

my_dict = nested_defaultdict(list, 3)
my_dict['a']['b']['c'].append('e')

前面的答案已经说明了如何生成两级或n级的默认dict。在某些情况下,您需要一个无限的:

def ddict():
返回defaultdict(ddict)
用法:

>>> d = ddict()
>>> d[1]['a'][True] = 0.5
>>> d[1]['b'] = 3
>>> import pprint; pprint.pprint(d)
defaultdict(<function ddict at 0x7fcac68bf048>,
            {1: defaultdict(<function ddict at 0x7fcac68bf048>,
                            {'a': defaultdict(<function ddict at 0x7fcac68bf048>,
                                              {True: 0.5}),
                             'b': 3})})
>d=ddict()
>>>d[1][a'][True]=0.5
>>>d[1]['b']=3
>>>进口pprint;pprint.pprint(d)
defaultdict(,
{1:defaultdict(,
{'a':defaultdict(,
{True:0.5}),
“b”:3})


此解决方案意味着获取所有d[x.a]并非易事,因为您需要反省每个键,看看它是否将x.a作为元组的第一个元素。如果您希望嵌套3层深度,则只需将其定义为3层:d=defaultdict(lambda:defaultdict(lambda:defaultdict(int)),效果非常好!你能解释一下这个语法背后的原因吗?@Jonathan:是的,当然,当你试图访问一个不存在的键时,会调用
defaultdict
(在本例中是
lambda:defaultdict(int)
)的参数,它的返回值将被设置为这个键的新值,这意味着在我们的例子中是
d的值[Key\u dont\u exist]
将是
defaultdict(int)
,如果您尝试从最后一个defaultdict访问密钥,即
d[Key\u dont\u exist][Key\u dont\u exist]
它将返回0,这是最后一个
defaultdict
的参数的返回值,即
int()
,希望这有帮助。
defaultdict
的参数应该是一个函数。
defaultdict(int)
是一个字典,而
lambda:defaultdict(int)
是返回字典的函数。@has2k1不正确。defaultdict的参数必须是可调用的。lambda是可调用的。@RickyLevi,如果你想让它工作,你可以说:
defaultdict(lambda:defaultdict(lambda:defaultdict(int)))
参见类似的问题。维基百科关于的文章中也有一些可能有用的信息。为了完成这里的循环,您可能希望使用
d=defaultdict(lambda:Counter())
而不是
d=defaultdict(lambda:defaultdict(int))
专门解决最初提出的问题。@gumption您可以使用
d=defaultdict(Counter())
在这种情况下不需要lambdacase@Deb您有一个小错误-请删除内括号,以便传递一个可调用的而不是
计数器
对象。即:
d=defaultdict(计数器)
Partial在这里也比lambda好,因为它可以递归地应用:)请参阅下面我的答案,了解一个通用的嵌套defaultdict工厂方法。@Campi递归应用程序不需要使用Partial,但可以给出一个用法示例吗?没有按照我预期的方式工作。
ndd=nested_defaultdict(dict)…ndd['a']['b']['c']['d']='e'
throws
KeyError:'b'
Hey David,在示例3中,您需要定义字典的深度(因为您也将默认工厂定义为字典。嵌套的默认dict(dict,3)将对您有效。这非常有用,谢谢!我注意到这会在
depth=0
处创建一个默认值,如果调用时深度未知,这可能并不总是需要的。通过添加一行
如果没有深度:返回默认值工厂()
,在函数的顶部,虽然可能有一个更优雅的解决方案。我喜欢它。它非常简单,但非常有用。谢谢!如何将它用于以下用例:第n级需要是int或alist@MonsieurBeilto“之前的答案已经说明了如何创建两级或n级默认dict”→
>>> d = ddict()
>>> d[1]['a'][True] = 0.5
>>> d[1]['b'] = 3
>>> import pprint; pprint.pprint(d)
defaultdict(<function ddict at 0x7fcac68bf048>,
            {1: defaultdict(<function ddict at 0x7fcac68bf048>,
                            {'a': defaultdict(<function ddict at 0x7fcac68bf048>,
                                              {True: 0.5}),
                             'b': 3})})