0

I'm trying to rewrite the following code

dct = {}
x = 'x'
y = 'y'
z = 'z'
if x not in dct:
    dct[x] = defaultdict(dict)
if y not in dct[x]:
    dct[x][y] = defaultdict(dict)
if z not in dct[x][y]:
    dct[x][y][z] = defaultdict(list)
dct[x][y][z]['b'].append(defaultdict(int))
dct[x][y][z]['b'][0]['g']+=1

Without the following lines:

if x not in dct:
    dct[x] = defaultdict(dict)
if y not in dct[x]:
    dct[x][y] = defaultdict(dict)
if z not in dct[x][y]:
    dct[x][y][z] = defaultdict(list)
dct[x][y][z]['b'].append(defaultdict(int))

Ideally I would like to have syntax such as

dct = 'state what it is'
dct[x][y][z]['b'][0]['g']+=1
bobsmith76
  • 160
  • 1
  • 9
  • 26
  • 2
    Does this answer your question? [Nested defaultdict of defaultdict](https://stackoverflow.com/questions/19189274/nested-defaultdict-of-defaultdict) – Kraigolas May 17 '22 at 20:51

2 Answers2

2

I wrote a customised implementation of defaultdict which can do this to an arbitrary depth, unlike the fixed depth from previous answers.

class DefaultDict(dict):
    def __missing__(self, name):
        rval=type(self)()
        self.__setitem__(name, rval)
        return rval

Here's some example usage:

>>> dct=DefaultDict()
>>> dct[0][1]['bees'][('any','hashable','object')]=2
>>> dct[0][1]['bees'][('any','hashable','object')]
2
>>> 0 in dct
True
>>> 1 in dct
False
>>> dct
{0: {1: {'bees': {('any', 'hashable', 'object'): 2}}}}
Mous
  • 953
  • 3
  • 14
  • @bobsmith76 This implementation works arbitrarily deep with all hashable objects – Mous May 17 '22 at 22:07
  • 1
    thanks i appreciate that. – bobsmith76 May 17 '22 at 23:50
  • It's also possibly worth mentioning that if you want to use `defaultdict` for some reason, you can either use the `tree=lambda:defaultdict:tree` from the linked question, but I dislike this for several reasons. (1) It's not anonymous, and so it's possible it could introduce bugs if you define another `tree`. A possible workaround is an anonymous class instance returning `self` in `__call__`, but that's untidy IMO. (2) It also doesn't allow for customisation based on the missing value, which may come in handy in future projects. This comment is mostly for future readers. – Mous May 18 '22 at 00:04
1

Use lambdas.

from collections import defaultdict as dd

dct = dd(lambda: dd(lambda: dd(int)))

dct["foo"][1][("a", 7)] += 1
amiasato
  • 914
  • 6
  • 14