С помощью рекурсии вы можете создать словарное понимание, которое выполнит это.
Это решение также учитывает, что вы можете захотеть объединить более двух словарей, сгладив список значений в этом случае.
def update_merge(d1, d2):
if isinstance(d1, dict) and isinstance(d2, dict):
# Unwrap d1 and d2 in new dictionary to keep non-shared keys with **d1, **d2
# Next unwrap a dict that treats shared keys
# If two keys have an equal value, we take that value as new value
# If the values are not equal, we recursively merge them
return {
**d1, **d2,
**{k: d1[k] if d1[k] == d2[k] else update_merge(d1[k], d2[k])
for k in {*d1} & {*d2}}
}
else:
# This case happens when values are merged
# It bundle values in a list, making sure
# to flatten them if they are already lists
return [
*(d1 if isinstance(d1, list) else [d1]),
*(d2 if isinstance(d2, list) else [d2])
]
Пример:
a = {"name": "john", "phone":"123123123",
"owns": {"cars": "Car 1", "motorbikes": "Motorbike 1"}}
b = {"name": "john", "phone":"123", "owns": {"cars": "Car 2"}}
update_merge(a, b)
# {'name': 'john',
# 'phone': ['123123123', '123'],
# 'owns': {'cars': ['Car 1', 'Car 2'], 'motorbikes': 'Motorbike 1'}}
Пример с объединением более двух объектов:
a = {"name": "john"}
b = {"name": "jack"}
c = {"name": "joe"}
d = update_merge(a, b)
d = update_merge(d, c)
d # {'name': ['john', 'jack', 'joe']}