是否存在无限嵌套的defaultdict的标准类?

时间:2010-11-14 15:52:10

标签: python dictionary nested infinite defaultdict

有人知道Python中是否存在无限可嵌套字典的标准类?

我发现自己重复这种模式:

d = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
d['abc']['def']['xyz'] += 1

如果我想添加“另一层”(例如d['abc']['def']['xyz']['wrt']),我必须定义另一个defaultdicts嵌套。

为了概括这种模式,我编写了一个简单的类来覆盖__getitem__以自动创建下一个嵌套字典。

e.g。

d = InfiniteDict(('count',0),('total',0))
d['abc']['def']['xyz'].count += 0.24
d['abc']['def']['xyz'].total += 1
d['abc']['def']['xyz']['wrt'].count += 0.143
d['abc']['def']['xyz']['wrt'].total += 1

但是,有没有人知道这个想法的预先实现?我试过谷歌搜索,但我不确定这会被称为什么。

6 个答案:

答案 0 :(得分:14)

这自然适用于递归定义。

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

答案 1 :(得分:11)

您可以从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

答案 2 :(得分:8)

我认为这种单线程是一种近乎完美的解决方案:

>>> from collections import defaultdict
>>> infinite_defaultdict = lambda: defaultdict(infinite_defaultdict)
>>> d = infinite_defaultdict() 
>>> d['x']['y']['z'] = 10
Raymond Hettinger在推特上发表了https://twitter.com/raymondh/status/343823801278140417

答案 3 :(得分:3)

理想的解决方案,受到某人的回答的启发:

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

答案 4 :(得分:1)

如果八年后,您仍在考虑如何使用单线获取此信息:

from collections import defaultdict

t = defaultdict(lambda: defaultdict(t.default_factory))

答案 5 :(得分:0)

这很接近:

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。

编辑: 啊,现在可以了 - 只需要添加一个__getattr__方法,这就是你想要的。

编辑2: 现在,除了整数之外,您还可以为属性定义其他工厂方法。但它们都必须是同一类型,不能计数浮点数和总数为int。