Is there a standard class for an infinitely nested defaultdict?

走远了吗. 提交于 2019-11-27 02:17:40

问题


Does anyone know if there's a standard class for an infinitely nestable dictionary in Python?

I'm finding myself repeating this pattern:

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

If I want to add "another layer" (e.g. d['abc']['def']['xyz']['wrt']), I have to define another nesting of defaultdicts.

To generalize this pattern, I've written a simple class that overrides __getitem__ to automatically create the next nested dictionary.

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

However, does anyone know of a pre-existing implementation of this idea? I've tried Googling, but I'm not sure what this would be called.


回答1:


You can derive from defaultdict to get the behavior you want:

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)

Usage of this class would look like this:

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


This lends itself naturally to a recursive definition.

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



回答3:


I think this one-liner is a nearly perfect solution:

>>> from collections import defaultdict
>>> infinite_defaultdict = lambda: defaultdict(infinite_defaultdict)
>>> d = infinite_defaultdict() 
>>> d['x']['y']['z'] = 10

by Raymond Hettinger on Twitter (https://twitter.com/raymondh/status/343823801278140417)




回答4:


The ideal solution, inspired by sth's answer:

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



回答5:


In case after eight years you are still thinking about how to get this with a one-liner:

from collections import defaultdict

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



回答6:


This is close:

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

It's not quite what you want, since the most deeply nested level does not have your default 0 values for 'count' or 'total'.

Edited: Ah, this works now - just needed to add a __getattr__ method, and this does what you want.

Edit 2: Now you can define other factory methods for the attributes, besides ints. But they all have to be the same type, can't have count be float and total be int.



来源:https://stackoverflow.com/questions/4178249/is-there-a-standard-class-for-an-infinitely-nested-defaultdict

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!