Nested defaultdict from defaultdict

Is there a way to make defaultdict also the default for defaultdict? (i.e. recursive defaultdict of infinite level?)

I want to be able to do:

x = defaultdict(...stuff...) x[0][1][0] {} 

So, I can do x = defaultdict(defaultdict) , but this is only the second level:

 x[0] {} x[0][0] KeyError: 0 

There are recipes that can do this. But can this be done simply using the usual defaultdict arguments?

Please note that here the question is asked how to make a recursive defaultdict of infinite level, so it differs from Python: defaultdict from defaultdict? which was how to make a two-level defaultdict.

I probably end up just using the bundle template, but when I realized that I did not know how to do this, it interested me.

+94
python recursion defaultdict
Oct 04 '13 at 19:28
source share
5 answers

For an arbitrary number of levels:

 def rec_dd(): return defaultdict(rec_dd) >>> x = rec_dd() >>> x['a']['b']['c']['d'] defaultdict(<function rec_dd at 0x7f0dcef81500>, {}) >>> print json.dumps(x) {"a": {"b": {"c": {"d": {}}}}} 

Of course, you could also do this with lambda, but I believe lambdas are less readable. In any case, it will look like this:

 rec_dd = lambda: defaultdict(rec_dd) 
+132
Oct 04 '13 at 19:33
source share

Other answers here will tell you how to create a defaultdict that contains an “infinitely many” defaultdict , but they cannot decide what, in my opinion, was your initial need, which was simply to have a two-level defaultdict.

You may have searched for:

 defaultdict(lambda: defaultdict(dict)) 

The reasons why you might prefer this design are as follows:

  • This is more explicit than a recursive solution, and therefore probably more comprehensible to the reader.
  • This allows the defaultdict be something other than a dictionary, for example: defaultdict(lambda: defaultdict(list)) or defaultdict(lambda: defaultdict(set))
+123
Jan 07 '15 at 1:11
source share

There is a great trick for this:

 tree = lambda: defaultdict(tree) 

Then you can create x with x = tree() .

+41
04 Oct '13 at 19:34 on
source share

Similar to the BrenBarn solution, but does not contain the variable name tree twice, so it works even after changes to the variable dictionary:

 tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a)))) 

Then you can create each new x with x = tree() .




For the def version, we can use the function closing area to protect the data structure from defect when existing instances stop working if the tree name bounces. It looks like this:

 from collections import defaultdict def tree(): def the_tree(): return defaultdict(the_tree) return the_tree() 
+18
04 Oct '13 at 20:01
source share

I would also like to offer more OOP-style implementations that support infinite nesting as well as properly formatted repr .

 class NestedDefaultDict(defaultdict): def __init__(self): super(NestedDefaultDict, self).__init__(NestedDefaultDict) def __repr__(self): return repr(dict(self)) 

Using:

 my_dict = NestedDefaultDict() my_dict['a']['b'] = 1 my_dict['a']['c']['d'] = 2 my_dict['b'] print(my_dict) # {'a': {'b': 1, 'c': {'d': 2}}, 'b': {}} 
0
May 28 '19 at 9:12
source share



All Articles