I'm using Python 3 and I'm trying to merge two dictionaries of dictionaries into one dictionary. I'm successful, however, when I add a new key/value pair to the new dictionary, it also adds it to both of the original dictionaries. I would like the original dictionaries to remain unchanged.
dict1 = {'key_val_1': {'a': '1', 'b': '2', 'c': '3'}}
dict2 = {'key_val_2': {'d': '4', 'e': '5', 'f': '6'}}
dict3 = dict1 | dict2
for x in dict3:
dict3[x]['g'] = '7'
The above code will append 'g': '7' to all 3 dictionaries and I only want to alter dict3. I have to assume that this is the intended behavior, but for the life of me I can't understand why (or how to get the desired results).
CodePudding user response:
Issue you are having is because dict3
consists reference to the sub-dicts in dict1
and dict2
. And the dict
objects are mutable
. So, when you change a dict
in one place, it effects all the place where it is referenced. You can verify it by using the id()
function. Example:
>>> print(id(dict1['key_val_1']))
>>> 140294429633472
>>> print(id(dict3['key_val_1']))
>>> 140294429633472
>>> print(id(dict2['key_val_2']))
>>> 140294429633728
>>> print(id(dict3['key_val_2']))
>>> 140294429633728
From above example you can verify that, the sub-dict in dict1
and dict2
are referenced in dict3
. So, when you modify them in dict3
the orginial dicts are also modified, as dict
are mutable
.
So, to solve your issue, you need to make a deep copy
of each sub-dict before merging them.
CodePudding user response:
I believe the root of your problem is your assumption that when concatenating the two dictionaries dict1 and dict2 that python makes a copy of the dictionaries before concatenating them. In fact Python simply creates a new object with pointers to each of the parts. With this in mind, when you change the contents of a part of dict3 you are in reality changing the underlying dictionaries dict1 and dict2. To remedy this condition, you need to make copies of the underlying dictionaries before concatenating them or merge them rather than concatenating them.
Using the copy function:
from copy import deepcopy
dict3 = deepcopy(dict1) | deepcopy(dict2)
Now dict3 contains independent copies of dict1 and dict2
To merge the dicts:
from copy import copy
def merge(d1, d2):
rslt = dict()
for k in d1.keys():
rslt[k] = d1[k].copy() #Note still necessary to copy underlying dict
for k in d2.keys():
rslt[k] = d2[k].copy()
return rslt
then use:
dict3 = merge(dict1, dict2)