Problem
I’d appreciate it if someone could explain this to me. This is incomprehensible to me.
I copy one dictionary into another, edit the second, and the two are now different. What is causing this?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
Asked by MadSc13ntist
Solution #1
Python never replicates objects by default. When you set dict2 = dict1, you’re making them both refer to the same identical dict object, so if you change it, all references to it will still refer to it in its present state.
If you want to clone a dict (which is uncommon), you must do it directly with the command.
dict2 = dict(dict1)
or
dict2 = dict1.copy()
Answered by Mike Graham
Solution #2
When you set dict2 = dict1, you’re not creating a duplicate of dict1. Instead, dict2 becomes a synonym for dict1.
Use the copy / deepcopy of the copy module to copy mutable types like dictionaries.
import copy
dict2 = copy.deepcopy(dict1)
Answered by Imran
Solution #3
Although dict.copy() and dict(dict1) make copies, they are only shallow copies. Copy.deepcopy(dict1) is necessary if you want a deep copy. Consider the following scenario:
>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10 # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40 # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3 # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
The Python copy module docs say this about shallow vs deep copies:
Answered by gpanda
Solution #4
In-depth information and an easy-to-remember formula:
When you type dict2 = dict1, you’re referring to dict1. Both dict1 and dict2 point to the same memory address. This is a common occurrence when dealing with mutable objects in Python. When working with mutable objects in Python, you must be cautious because they are difficult to debug.
To separate dict2 from dict1, use the copy(shallow copy) and deepcopy methods from Python’s copy module instead of dict2 = dict1.
The proper procedure is as follows:
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?"
>>> dict2
{'key1': 'value1', 'key2': 'WHY?'}
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>> id(dict1)
140641178056312
>>> id(dict2)
140641176198960
>>>
As you can see the id of both dict1 and dict2 are different, which means both are pointing/referencing to different locations in the memory.
This solution works for dictionaries with immutable values, this is not the correct solution for those with mutable values.
Eg:
>>> import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': False}}
>>> id(dict1)
140641197660704
>>> id(dict2)
140641196407832
>>> id(dict1["key2"])
140641176198960
>>> id(dict2["key2"])
140641176198960
You can see that even though we applied copy for dict1, the value of mutable is changed to false on both dict2 and dict1 even though we only change it on dict2. This is because the value of a mutable dict component of the dict1 was modified. When we apply a copy on dict, it will only do a shallow copy which means it copies all the immutable values into a new dict and does not copy the mutable values but it will reference them.
n is a deepycopy of dict1 that creates a new dict with all of the values, including mutable values, copied.
>>>import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = copy.deepcopy(dict1)
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> id(dict1)
140641196228824
>>> id(dict2)
140641197662072
>>> id(dict1["key2"])
140641178056312
>>> id(dict2["key2"])
140641197662000
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': True}}
As you can see, the ids differ, implying that dict2 is an entirely new dict containing all of the data from dict1.
If you wish to update any of the mutable values without impacting the original dict, you’ll need to utilise Deepcopy. If not, shallow copy can be used. Deepcopy is slow as it works recursively to copy any nested values in the original dict and also takes extra memory.
Answered by Vkreddy
Solution #5
The ** unpackaging operator is an easier approach to achieve a shallow copy in Python 3.5+. Pep 448 defined it.
>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}
** unpacks the dictionary into a new dictionary and assigns it to dict2.
We can also verify that each dictionary has its own identifier.
>>>id(dict1)
178192816
>>>id(dict2)
178192600
Copy if a deep copy is required. deepcopy() is still the preferred method.
Answered by PabTorre
Post is based on https://stackoverflow.com/questions/2465921/how-to-copy-a-dictionary-and-only-edit-the-copy