Це питання давнє, але я приземлився тут, шукаючи рішення "глибокого злиття". Наведені вище відповіді надихнули на наступне. Я закінчив писати свої власні, оскільки були помилки у всіх перевірених версіях. Критична пропущена точка була, на деякій довільній глибині двох вхідних диктовок, для деякого ключа, k, дерево рішень, коли d [k] або u [k] не є диктатом, було несправним.
Крім того, це рішення не потребує рекурсії, що симетричніше як dict.update()
працює, так і повертається None
.
import collections
def deep_merge(d, u):
"""Do a deep merge of one dict into another.
This will update d with values in u, but will not delete keys in d
not found in u at some arbitrary depth of d. That is, u is deeply
merged into d.
Args -
d, u: dicts
Note: this is destructive to d, but not u.
Returns: None
"""
stack = [(d,u)]
while stack:
d,u = stack.pop(0)
for k,v in u.items():
if not isinstance(v, collections.Mapping):
# u[k] is not a dict, nothing to merge, so just set it,
# regardless if d[k] *was* a dict
d[k] = v
else:
# note: u[k] is a dict
# get d[k], defaulting to a dict, if it doesn't previously
# exist
dv = d.setdefault(k, {})
if not isinstance(dv, collections.Mapping):
# d[k] is not a dict, so just set it to u[k],
# overriding whatever it was
d[k] = v
else:
# both d[k] and u[k] are dicts, push them on the stack
# to merge
stack.append((dv, v))