Python 是否存在用于无限嵌套defaultdict的标准类?
有人知道Python中是否有一个无限嵌套字典的标准类吗 我发现自己在重复这个模式:Python 是否存在用于无限嵌套defaultdict的标准类?,python,dictionary,nested,infinite,defaultdict,Python,Dictionary,Nested,Infinite,Defaultdict,有人知道Python中是否有一个无限嵌套字典的标准类吗 我发现自己在重复这个模式: d = defaultdict(lambda: defaultdict(lambda: defaultdict(int))) d['abc']['def']['xyz'] += 1 如果我想添加“另一层”(例如,d['abc']['def']['xyz']['wrt']),我必须定义另一个defaultdicts嵌套 为了推广这种模式,我编写了一个简单的类,它覆盖\uuuu getitem\uuuu以自动创建下
d = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
d['abc']['def']['xyz'] += 1
如果我想添加“另一层”(例如,d['abc']['def']['xyz']['wrt']
),我必须定义另一个defaultdicts嵌套
为了推广这种模式,我编写了一个简单的类,它覆盖\uuuu getitem\uuuu
以自动创建下一个嵌套字典
e、 g
然而,有人知道这个想法已经存在了吗?我尝试过谷歌搜索,但我不确定这将被称为什么。这自然适合递归定义
>>> import collections
>>> def nested_dd():
... return collections.defaultdict(nested_dd)
...
>>> foo = nested_dd()
>>> foo
defaultdict(<function nested_dd at 0x023F0E30>, {})
>>> foo[1][2]=3
>>> foo[1]
defaultdict(<function nested_dd at 0x023F0E30>, {2: 3})
>>> foo[1][2]
3
导入集合
>>>def嵌套的_dd():
... 返回集合.defaultdict(嵌套的\u dd)
...
>>>foo=nested_dd()
>>>福
defaultdict(,{})
>>>foo[1][2]=3
>>>傅[1]
defaultdict(,{2:3})
>>>foo[1][2]
3.
这很接近:
class recursivedefaultdict(defaultdict):
def __init__(self, attrFactory=int):
self.default_factory = lambda : type(self)(attrFactory)
self._attrFactory = attrFactory
def __getattr__(self, attr):
newval = self._attrFactory()
setattr(self, attr, newval)
return newval
d = recursivedefaultdict(float)
d['abc']['def']['xyz'].count += 0.24
d['abc']['def']['xyz'].total += 1
data = [
('A','B','Z',1),
('A','C','Y',2),
('A','C','X',3),
('B','A','W',4),
('B','B','V',5),
('B','B','U',6),
('B','D','T',7),
]
table = recursivedefaultdict(int)
for k1,k2,k3,v in data:
table[k1][k2][k3] = v
这不是您想要的,因为嵌套最深的级别没有“count”或“total”的默认0值
编辑:
啊,现在可以了-只需要添加一个\uuu getattr\uuuu
方法,就可以了
编辑2:
现在,您可以为属性定义除INT之外的其他factory方法。但它们必须是相同的类型,不能让count为float,total为int。您可以从
defaultdict
派生出您想要的行为:
class InfiniteDict(defaultdict):
def __init__(self):
defaultdict.__init__(self, self.__class__)
class Counters(InfiniteDict):
def __init__(self):
InfiniteDict.__init__(self)
self.count = 0
self.total = 0
def show(self):
print "%i out of %i" % (self.count, self.total)
此类的用法如下所示:
>>> d = Counters()
>>> d[1][2][3].total = 5
>>> d[1][2][3].show()
0 out of 5
>>> d[5].show()
0 out of 0
由某事物的答案启发的理想解决方案:
from collections import defaultdict
class InfiniteDict(defaultdict):
def __init__(self, **kargs):
defaultdict.__init__(self, lambda: self.__class__(**kargs))
self.__dict__.update(kargs)
d = InfiniteDict(count=0, total=0)
d['abc']['def'].count += 0.25
d['abc']['def'].total += 1
print d['abc']['def'].count
print d['abc']['def'].total
d['abc']['def']['xyz'].count += 0.789
d['abc']['def']['xyz'].total += 1
print d['abc']['def']['xyz'].count
print d['abc']['def']['xyz'].total
我认为这一行是一个近乎完美的解决方案:
>>> from collections import defaultdict
>>> infinite_defaultdict = lambda: defaultdict(infinite_defaultdict)
>>> d = infinite_defaultdict()
>>> d['x']['y']['z'] = 10
Raymond Hettinger在Twitter上的文章()如果八年后你仍然在考虑如何用一句话来表达:
from collections import defaultdict
t = defaultdict(lambda: defaultdict(t.default_factory))
非常整洁,但与我发布的答案有相同的缺陷,不支持叶节点上的“count”和“total”零值。@Paul--的确;你不能既有蛋糕又吃!对
count
和total
的特殊支持破坏了对称性,因此必须将其硬连接到类的某个地方。@aaronasterling:任何递归限制都没有问题,因为函数不会递归调用自身。对了,我错过了这一部分并一直在寻找:)对不起,katriealex。对不起,但我不认为这是可行的,因为如果你看到OP的问题,他正在用默认的默认值进行大量的计算,而不仅仅是赋值!!!谢谢这与我所寻找的最接近,并帮助我找到了确切的解决方案。次要建议:您可以使用functools.partial(键入(self),attrFactory)
。此解决方案的排名应该更高!
from collections import defaultdict
t = defaultdict(lambda: defaultdict(t.default_factory))