- Published on
Python dictionary like Clojure map
- Authors
- Name
- Piotr Kurnik
Imagine you want to create something like this:
expected = {"Continent": {"Europe": {"Poland": 38,
"Germany": 82}}}
In Clojure you can use assoc-in
to produce such data structure. It’s very useful because we start with empty map {}
(-> {}
(assoc-in [:Continent :Europe :Poland] 38)
(assoc-in [:Continent :Europe :Germany] 82)
)
If you try to do something similar in Python you will get a KeyError
data = dict()
data["Continent"]["Europe"]["Poland"] = 38
You can use collections.defaultdict
to create a dictionary that has the same properties as Clojure maps:
from collections import defaultdict
def default_dict_factory():
return defaultdict(default_dict_factory)
data = default_dict_factory()
data["Continent"]["Europe"]["Poland"] = 38
data["Continent"]["Europe"]["Germany"] = 38
print(data)
That works!
How does that work?
defaultdict
accepts factory method, which is executed when the key is not found in the dictionary. And that is what default_dict_factory
returns.
In theory you could do:
data = defaultdict(dict)
That would allow you do run something like that:
data["Continent"] = "Europe"
But as soon as you want to run:
data["Continent"]["Europe"]
You will get KeyError
. Why?
Because in this case factory method is dict
which means that when key is not found, a dict
is created. And dict
raises KeyError
.
If you use default_dict_factory
, on missing key defaultdict
will be created, which is what you want.
Using deafultdict
is a simple way of creating Python dictionaries which work like Clojure maps. I use them quite frequently, hope you will find it useful too.