I am having a saved list of Python dict keys:
['level_one', 'level_two', 'test']
These are the keys of a dictionary:
mydict = {
'level_one' : {
'level_two' : {
'test' : "Hello World"
}
}
}
Normally I could set the test
key like this:
mydict['level_one']['level_two']['test'] = "Hello StackOverflow"
Unfortunately, the list/dict are generated on the fly, and I don't know how deep it can go. Is there a possibility to update the dict key by the list of keys without using braces?
I only was able to reflect this functionality for getting the string:
def deepGet(sourceDict, *keys):
return reduce(lambda d, k: d.get(k) if d else None, keys, sourceDict)
> deepGet(mydict, *['level_one', 'level_two', 'test'])
>> Hello World
Not a duplicate. This is regarding setting, not getting of nested dictionary.
There is now a way to deep set values dynamically, without changing the container type to a defaultdict or some other dynamically creating type: glom.assign().
A usage example with your case:
import glom
target = {}
path = 'level_one.level_two.test'
glom.assign(target, path, 'hello world', missing=dict)
# {'level_one': {'level_two': {'test': 'hello world'}}}
Notice we passed the missing=dict
, telling glom to create missing keys with the built-in dict constructor. You'll also need to pip install glom
, but it's pure-Python and compatible with Python 2, 3, and PyPy.
There's a lot more you can do with glom, especially around deep getting and setting. I should know, since (full disclosure) I created it. That means if you find a gap, you should let me know!
We need a defaultdict
that will keep making new instances of itself all the way down.
import collections
recursive_dict = lambda: collections.defaultdict(recursive_dict)
mydict = recursive_dict()
At this point, you can simplify your deepGet
to just use operator.getitem
instead of the lambda you have now. operator.getitem
is "shorthand" for lambda a, b: a[b]
.
As for setting a key, you can just write a loop:
keys = ['level_one', 'level_two', 'test']
d = mydict
for key in keys[:-1]:
d = d[key]
d[keys[-1]] = 'Hello World'
If dictionaries are missing, the defaultdict will silently create them, no need to check for them first.
Converting this to a reduce()
call is left as an exercise for the reader.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With