Home > Enterprise >  python merging nested dictionaries into a new dictionary and update that dictionary without affectin
python merging nested dictionaries into a new dictionary and update that dictionary without affectin

Time:06-12

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)
  • Related