This is a very interesting and a very practical situation once can encounter.
There are numerous implementation each solves certain things and miss out few edge scenarios.
Possible solutions and varying answer can be found in these titles.
What is the best way to implement nested dictionaries?
What's the best way to initialize a dict of dicts in Python?
Set nested dict value and create intermediate keys
Also, there numerous gists and blogs are found on this requirement 'autovivification', including a wikipedia presence.
http://blog.yjl.im/2013/08/autovivification-in-python.html
https://news.ycombinator.com/item?id=3881171
https://gist.github.com/hrldcpr/2012250
https://en.wikipedia.org/wiki/Autovivification
http://blogs.fluidinfo.com/terry/2012/05/26/autovivification-in-python-nested-defaultdicts-with-a-specific-final-type/
While the above implementation are handy once edge case could be still problematic. At the time of this writing, no implementation has handled well whether there is a primitive sitting and blocking the nest.
Here are the 3 mains ways this question and related questions are answered here in StackOverflow.
Write a helper method, that accepts dictionary, value and list of nested keys
Works well with plain dict objects, but lacks the usual square bracket syntax,
Use Defaultdict and write custom class, Fundamentally this works since default dict supplies {} for missing keys
Great syntax, but works only for the objects that were created using the custom class.
Use tuples to store and retrieve (https://stackoverflow.com/a/651930/968442)
The Worst idea of all, Not even should be claimed as solution, Here is why
mydict = {}
mydict['foo', 'bar', 'baz'] = 1
print mydict['foo', 'bar', 'baz']
Will work fine, But when you access mydict['foo', 'bar']
the expectation will be {'baz':1}
, not a KeyError
This basically destroys the idea of iterable & nested structure
Of the three approaches, my bet goes to option 1. By writing a tiny helper method the edge cases can be resolved pragmatically, here is my implementation.
def sattr(d, *attrs):
# Adds "val" to dict in the hierarchy mentioned via *attrs
for attr in attrs[:-2]:
# If such key is not found or the value is primitive supply an empty dict
if d.get(attr) is None or isinstance(d.get(attr), dict):
d[attr] = {}
d = d[attr]
d[attrs[-2]] = attrs[-1]
Now
my_pets = {'Rudolf': {'animal': 'cat', 'legs': 4}}
sattr(my_pets, 'Rudolf', 'legs', 'front-right', 'injured', True)
sattr(my_pets, 'Rudolf', 'legs', 'front-left', 'injured', False)
will produce
{'Rudolf': {'legs': 4, 'animal': 'cat'}}
{'Rudolf': {'legs': {'front-right': {'injured': True}}, 'animal': 'cat'}}
{'Rudolf': {'legs': {'front-left': {'injured': False}, 'front-right': {'injured': True}}, 'animal': 'cat'}}