Update value of a nested dictionary of varying depth
@FM's answer has the right general idea, i.e. a recursive solution, but somewhat peculiar coding and at least one bug. I'd recommend, instead:
Python 2:
import collections
def update(d, u):
for k, v in u.iteritems():
if isinstance(v, collections.Mapping):
d[k] = update(d.get(k, {}), v)
else:
d[k] = v
return d
Python 3:
import collections.abc
def update(d, u):
for k, v in u.items():
if isinstance(v, collections.abc.Mapping):
d[k] = update(d.get(k, {}), v)
else:
d[k] = v
return d
The bug shows up when the "update" has a k
, v
item where v
is a dict
and k
is not originally a key in the dictionary being updated -- @FM's code "skips" this part of the update (because it performs it on an empty new dict
which isn't saved or returned anywhere, just lost when the recursive call returns).
My other changes are minor: there is no reason for the if
/else
construct when .get
does the same job faster and cleaner, and isinstance
is best applied to abstract base classes (not concrete ones) for generality.
Took me a little bit on this one, but thanks to @Alex's post, he filled in the gap I was missing. However, I came across an issue if a value within the recursive dict
happens to be a list
, so I thought I'd share, and extend his answer.
import collections
def update(orig_dict, new_dict):
for key, val in new_dict.iteritems():
if isinstance(val, collections.Mapping):
tmp = update(orig_dict.get(key, { }), val)
orig_dict[key] = tmp
elif isinstance(val, list):
orig_dict[key] = (orig_dict.get(key, []) + val)
else:
orig_dict[key] = new_dict[key]
return orig_dict