C'est en fait assez délicat - en particulier si vous voulez un message d'erreur utile lorsque les choses sont incohérentes, tout en acceptant correctement les entrées dupliquées mais cohérentes (ce qu'aucune autre réponse ne fait ).
Si vous n'avez pas un grand nombre d'entrées, une fonction récursive est la plus simple :
from functools import reduce
def merge(a, b, path=None):
"merges b into a"
if path is None: path = []
for key in b:
if key in a:
if isinstance(a[key], dict) and isinstance(b[key], dict):
merge(a[key], b[key], path + [str(key)])
elif a[key] == b[key]:
pass # same leaf value
else:
raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
else:
a[key] = b[key]
return a
# works
print(merge({1:{"a":"A"},2:{"b":"B"}}, {2:{"c":"C"},3:{"d":"D"}}))
# has conflict
merge({1:{"a":"A"},2:{"b":"B"}}, {1:{"a":"A"},2:{"b":"C"}})
noter qu'il s'agit d'une mutation a
- le contenu de b
sont ajoutés à a
(qui est également renvoyée). Si vous souhaitez conserver a
vous pourriez l'appeler ainsi merge(dict(a), b)
.
agf a fait remarquer (ci-dessous) que vous pouvez avoir plus de deux dicts, auquel cas vous pouvez utiliser :
reduce(merge, [dict1, dict2, dict3...])
où tout sera ajouté à dict1
.
Note : J'ai modifié ma réponse initiale pour faire muter le premier argument ; cela rend la "réduction" plus facile à expliquer.