1

Why does the below work

x = defaultdict(dict)
for a,b,c in [('eg', 'ef', 'ee'), ('eg', 'eu', 'e4'), ('kk', 'nn', 'bb')]:
    x[a][b] = c

And the below throws an error ?

x = defaultdict(dict)
for a,b,c,d in [('eg', 'ef', 'ee', 'gg'), ('eg', 'eu', 'e4', 'hh'),
                ('kk', 'nn', 'bb', 'ff')]:
    x[a][b][c] = d
Łukasz Rogalski
  • 18,883
  • 6
  • 53
  • 84
Ani
  • 101
  • 2
  • 9
  • 1
    Because `defaultdict(dict)` is only good for two levels of nesting? The inner dictionary `d[a]` is just a vanilla dictionary. – jonrsharpe Sep 27 '16 at 12:56
  • @DanielLee that is not true; it only fixes part of the problem – jonrsharpe Sep 27 '16 at 12:57
  • If you need three levels deep use `defaultdict(lambda: defaultdict(dict))`. – Steven Rumbalski Sep 27 '16 at 13:03
  • 1
    @StevenRumbalski: Or slightly more efficient (avoids Python level calls through lambdas) and concise: `defaultdict(defaultdict(dict).copy)` (no, the efficiency likely doesn't matter, I just like finding ways to avoid `lambda`s whenever possible :-) ) – ShadowRanger Sep 27 '16 at 13:06
  • Have a look at [this question](http://stackoverflow.com/questions/5369723/multi-level-defaultdict-with-variable-depth-in-python) – chthonicdaemon Sep 27 '16 at 13:08
  • 1
    Also, don't re-use `d` as a loop parameter as that will clobber the dictionary of the same name. – PM 2Ring Sep 27 '16 at 13:09
  • If you do not need the grouping behavior of nested dictionaries you can use tuple keys: `my_dict[a, b, c] = d`. – Steven Rumbalski Sep 27 '16 at 13:10
  • I intend to group them based on the first value in the tuple. – Ani Sep 27 '16 at 13:15
  • 1
    See [_What is the best way to implement nested dictionaries in Python?_](http://stackoverflow.com/questions/635483/what-is-the-best-way-to-implement-nested-dictionaries-in-python) – martineau Sep 27 '16 at 13:24
  • Possible duplicate of [defaultdict of defaultdict, nested](http://stackoverflow.com/questions/19189274/defaultdict-of-defaultdict-nested) – Łukasz Rogalski Sep 27 '16 at 22:42

1 Answers1

2

The issue here is that defaultdict accepts a callable, which is used as a factory to generate the value when a key is missing. Once you understand that, the behaviour is clear:

x = defaultdict(dict)
x                    # it's a default dict
x['a']               # it's just a dict()
x['a']['b'] = 'c'    # it's just setting the 'b' item in the dict x['a']
x['a']['b']['z']     # oops, error, because x['a']['b'] is not a dict!

If you only require a finite level of nesting, using a plain old dict with tuple keys is usually a much easier data structure to work with. That will work fine for both the 2-d and 3-d examples shown in your question.

If you require arbitrary levels of nesting, however, you can consider the recursive defaultdict example shown here.

Community
  • 1
  • 1
wim
  • 266,989
  • 79
  • 484
  • 630