Welcome, guest | Sign In | My Account | Store | Cart

A nested dictionary which creates subnotes on the fly.

Python, 9 lines
1
2
3
4
5
6
7
8
9
class auto_dict(dict):
    def __getitem__(self, key):
        return self.setdefault(key, self.__class__())


if __name__ == "__main__":
    d = auto_dict()
    d["foo"]["bar"]["baz"] = 42
    print d

After reading an article about autovivication hashes in Ruby, I tried to find a simpler solution for Python.

I want a nested dictionary like objects, which can be indexed in multiple dimensions and which elements are automatically created, when accessed.

The implementation I used before is about 10 lines of code, this one is shorter and imho more elegant.

It used the setdefault() method of a dictionay to add another instance of self.__class__ as the default value for every key.

2 comments

Ruslan Spivak 16 years, 1 month ago  # | flag

another form.

class default_dict(dict):
    def __missing__(self, key):
        self[key] = value = self.__class__()
        return value

>>> d = default_dict()
>>> d
{}
>>> d['a']['b']['c'] = 777
>>> d
{'a': {'b': {'c': 777}}}

If there is no need for deeply nested dicts defaultdict to the rescue:

>>> from collections import defaultdict
>>> d = defaultdict(dict)
>>> d
defaultdict(, {})
>>> d['a']['b'] = 33
>>> d
defaultdict(, {'a': {'b': 33}})
David Moss 14 years, 2 months ago  # | flag

A small note of caution

The form using __missing__ only works with Python 2.5.x and higher!

In older Python versions it silently fails, throwing KeyError exceptions when the expected intermediate keys have not been created as expected.

Created by Mirko Dziadzka on Wed, 19 Dec 2007 (PSF)
Python recipes (4591)
Mirko Dziadzka's recipes (2)

Required Modules

  • (none specified)

Other Information and Tasks