Alex B Alex B - 4 months ago 22
Python Question

Equivalent of Clojure's "assoc-in" and "get-in" in Python

In Clojure you can update a map (dict) with

assoc-in
and create key path automatically if it don't exist.

(assoc-in {:a 1 :b 3} [:c :d] 33)
{:a 1, :c {:d 33}, :b 3}


Same for
get-in
: you can specify a path of keys (or list indices) and it will return the value specified by the path,
nil
if it does not exist.

(get-in {:a 1, :c {:d 33}, :b 3} [:c :d])
33
(get-in {:a 1, :c {:d 33}, :b 3} [:c :e])
nil


Is there a Python equivalent or a comparable shortcut out of the box? (yes, I know I can write dodgy dict wrappers myself, but I'd like to avoid it).

Answer

How about this?

>>> from collections import defaultdict
>>> def cdict():
...     return defaultdict(cdict)
... 
>>> d = cdict()
>>> d['a']=1
>>> d['b']=3
>>> d
defaultdict(<function cdict at 0x28d3ed8>, {'a': 1, 'b': 3})
>>> d['c']['d'] = 33
>>> d['c']['d']
33
>>> d
defaultdict(<function cdict at 0x28d3ed8>, {'a': 1, 'c': defaultdict(<function cdict at 0x28d3ed8>, {'e': defaultdict(<function cdict at 0x28d3ed8>, {}), 'd': 33}), 'b': 3})
>>> d['c']['e']
defaultdict(<function cdict at 0x28d3ed8>, {})
>>> 

It returns an empty cdict() on key not found rather than nil or None but otherwise I think it behaves the same.

The repr could do with a bit of work!