I set dict2 = dict1
. When I edit dict2
, the original dict1
also changes. Why?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
dict1
and dict2
point to the same dict.
Python never implicitly copies objects. When you set dict2 = dict1
, you are making them refer to the same exact dict object, so when you mutate it, all references to it keep referring to the object in its current state.
If you want to copy the dict (which is rare), you have to do so explicitly with
dict2 = dict(dict1)
or
dict2 = dict1.copy()
When you assign dict2 = dict1
, you are not making a copy of dict1
, it results in dict2
being just another name for dict1
.
To copy the mutable types like dictionaries, use copy
/ deepcopy
of the copy
module.
import copy
dict2 = copy.deepcopy(dict1)
While dict.copy()
and dict(dict1)
generates a copy, they are only shallow copies. If you want a deep copy, copy.deepcopy(dict1)
is required. An example:
>>> 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}}
Regarding shallow vs deep copies, from the Python copy
module docs:
The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances): A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original. A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
w=copy.deepcopy(x)
is the key line.
dict2 = dict1
and dict2 = copy.deepcopy(dict1)
?
In Depth and an easy way to remember:
Whenever you do dict2 = dict1, dict2 refers to dict1. Both dict1 and dict2 points to the same location in the memory. This is just a normal case while working with mutable objects in python. When you are working with mutable objects in python you must be careful as it is hard to debug.
Instead of using dict2 = dict1, you should be using copy(shallow copy) and deepcopy method from python's copy module to separate dict2 from dict1.
The correct way is:
>>> 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 we changed the value of a mutable dict part of the dict1. 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.
The ultimate solution is to do a deepycopy of dict1 to completely create a new dict with all the values copied, including mutable values.
>>>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, id's are different, it means that dict2 is completely a new dict with all the values in dict1.
Deepcopy needs to be used if whenever you want to change any of the mutable values without affecting the original dict. If not you can use shallow copy. Deepcopy is slow as it works recursively to copy any nested values in the original dict and also takes extra memory.
On python 3.5+ there is an easier way to achieve a shallow copy by using the ** unpackaging operator. Defined by Pep 448.
>>>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?!'}
** unpackages the dictionary into a new dictionary that is then assigned to dict2.
We can also confirm that each dictionary has a distinct id.
>>>id(dict1)
178192816
>>>id(dict2)
178192600
If a deep copy is needed then copy.deepcopy() is still the way to go.
dict2 = {**dict1, 'key3':'value3'}
The best and the easiest ways to create a copy of a dict in both Python 2.7 and 3 are...
To create a copy of simple(single-level) dictionary:
1. Using dict() method, instead of generating a reference that points to the existing dict.
my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1) # {'message':'Hello Python'}
my_dict2 = dict(my_dict1)
print(my_dict2) # {'message':'Hello Python'}
# Made changes in my_dict1
my_dict1["name"] = "Emrit"
print(my_dict1) # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2) # {'message':'Hello Python'}
2. Using the built-in update() method of python dictionary.
my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2) # {'message':'Hello Python'}
# Made changes in my_dict1
my_dict1["name"] = "Emrit"
print(my_dict1) # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2) # {'message':'Hello Python'}
To create a copy of nested or complex dictionary:
Use the built-in copy module, which provides a generic shallow and deep copy operations. This module is present in both Python 2.7 and 3.*
import copy
my_dict2 = copy.deepcopy(my_dict1)
dict()
creates a shallow copy not a deep copy. Meaning that if you have a nested dict
then the outer dict
will be a copy but the inner dict will be a reference to the original inner dict.
You can also just make a new dictionary with a dictionary comprehension. This avoids importing copy.
dout = dict((k,v) for k,v in mydict.items())
Of course in python >= 2.7 you can do:
dout = {k:v for k,v in mydict.items()}
But for backwards compat., the top method is better.
d2 = dict.copy(d1)
doesn't require any imports either.
d2 = d1.copy()
dict.items
already returns a key/value pair iterable. So you can just use dict(mydict.items())
(you can also just use dict(mydict)
). It may be useful to have the comprehension if you wanted to filter the entries.
In addition to the other provided solutions, you can use **
to integrate the dictionary into an empty dictionary, e.g.,
shallow_copy_of_other_dict = {**other_dict}
.
Now you will have a "shallow" copy of other_dict
.
Applied to your example:
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>
Pointer: Difference between shallow and deep copys
Assignment statements in Python do not copy objects, they create bindings between a target and an object.
so, dict2 = dict1
, it results another binding between dict2
and the object that dict1
refer to.
if you want to copy a dict, you can use the copy module
. The copy module has two interface:
copy.copy(x)
Return a shallow copy of x.
copy.deepcopy(x)
Return a deep copy of x.
The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):
A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
For example, in python 2.7.9:
>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')
and the result is:
>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]
You can copy and edit the newly constructed copy in one go by calling the dict
constructor with additional keyword arguments:
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}
This confused me too, initially, because I was coming from a C background.
In C, a variable is a location in memory with a defined type. Assigning to a variable copies the data into the variable's memory location.
But in Python, variables act more like pointers to objects. So assigning one variable to another doesn't make a copy, it just makes that variable name point to the same object.
dict1
is a symbol that references an underlying dictionary object. Assigning dict1
to dict2
merely assigns the same reference. Changing a key's value via the dict2
symbol changes the underlying object, which also affects dict1
. This is confusing.
It is far easier to reason about immutable values than references, so make copies whenever possible:
person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26} # does not mutate person dict
This is syntactically the same as:
one_year_later = dict(person, age=26)
Every variable in python (stuff like dict1
or str
or __builtins__
is a pointer to some hidden platonic "object" inside the machine.
If you set dict1 = dict2
,you just point dict1
to the same object (or memory location, or whatever analogy you like) as dict2
. Now, the object referenced by dict1
is the same object referenced by dict2
.
You can check: dict1 is dict2
should be True
. Also, id(dict1)
should be the same as id(dict2)
.
You want dict1 = copy(dict2)
, or dict1 = deepcopy(dict2)
.
The difference between copy
and deepcopy
? deepcopy
will make sure that the elements of dict2
(did you point it at a list?) are also copies.
I don't use deepcopy
much - it's usually poor practice to write code that needs it (in my opinion).
dict2 = dict1
does not copy the dictionary. It simply gives you the programmer a second way (dict2
) to refer to the same dictionary.
>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1
There are many ways to copy Dict object, I simply use
dict_1 = {
'a':1,
'b':2
}
dict_2 = {}
dict_2.update(dict_1)
dict_2 = dict_1.copy()
is much more efficient and logical.
the following code, which is on dicts which follows json syntax more than 3 times faster than deepcopy
def CopyDict(dSrc):
try:
return json.loads(json.dumps(dSrc))
except Exception as e:
Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
return deepcopy(dSrc)
As others have explained, the built-in dict
does not do what you want. But in Python2 (and probably 3 too) you can easily create a ValueDict
class that copies with =
so you can be sure that the original will not change.
class ValueDict(dict):
def __ilshift__(self, args):
result = ValueDict(self)
if isinstance(args, dict):
dict.update(result, args)
else:
dict.__setitem__(result, *args)
return result # Pythonic LVALUE modification
def __irshift__(self, args):
result = ValueDict(self)
dict.__delitem__(result, args)
return result # Pythonic LVALUE modification
def __setitem__(self, k, v):
raise AttributeError, \
"Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)
def __delitem__(self, k):
raise AttributeError, \
"Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)
def update(self, d2):
raise AttributeError, \
"Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""
# test
d = ValueDict()
d <<='apples', 5
d <<='pears', 8
print "d =", d
e = d
e <<='bananas', 1
print "e =", e
print "d =", d
d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']
# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1
# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."
Please refer to the lvalue modification pattern discussed here: Python 2.7 - clean syntax for lvalue modification. The key observation is that str
and int
behave as values in Python (even though they're actually immutable objects under the hood). While you're observing that, please also observe that nothing is magically special about str
or int
. dict
can be used in much the same ways, and I can think of many cases where ValueDict
makes sense.
i ran into a peculiar behavior when trying to deep copy dictionary property of class w/o assigning it to variable
new = copy.deepcopy(my_class.a)
doesn't work i.e. modifying new
modifies my_class.a
but if you do old = my_class.a
and then new = copy.deepcopy(old)
it works perfectly i.e. modifying new
does not affect my_class.a
I am not sure why this happens, but hope it helps save some hours! :)
my_class.a
?
Copying by using a for loop:
orig = {"X2": 674.5, "X3": 245.0}
copy = {}
for key in orig:
copy[key] = orig[key]
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}
deepcopy
, which is built expressly for this purpose?
def _copy_dict(dictionary:dict): return {key: dictionary[key] for key in dictionary}
You can use directly:
dict2 = eval(repr(dict1))
where object dict2 is an independent copy of dict1, so you can modify dict2 without affecting dict1.
This works for any kind of object.
__repr__
to be reconstructed by eval, nor may the object's class be in the current scope to be called. Even sticking with built-in types, this will fail if the same object is stored under multiple keys, as dict2
would then have two separate objects. A self-referential dictionary, where dict1
contains itself, will instead contain Ellipsis
. It would be better to use dict1.copy()
Another cleaner way would be using json. see below code
>>> a = [{"name":"Onkar","Address": {"state":"MH","country":"India","innerAddress":{"city":"Pune"}}}]
>>> b = json.dumps(a)
>>> b = json.loads(b)
>>> id(a)
2334461105416
>>> id(b)
2334461105224
>>> a[0]["Address"]["innerAddress"]["city"]="Nagpur"
>>> a
[{'name': 'Onkar', 'Address': {'state': 'MH', 'country': 'India', 'innerAddress': {'city': 'Nagpur'}}}]
>>> b
[{'name': 'Onkar', 'Address': {'state': 'MH', 'country': 'India', 'innerAddress': {'city': 'Pune'}}}]
>>> id(a[0]["Address"]["innerAddress"])
2334460618376
>>> id(b[0]["Address"]["innerAddress"])
2334424569880
To create another dictionary do json.dumps() and then json.loads() on the same dictionary object. You will have separate dict object.
Success story sharing
dir(1)
to see that), but they are implicitly copied.int
,float
, andbool
instances are real Python objects, and b) objects of these types are not implicitly copied when you pass them, not at a semantic Python level for sure and not even as an implementation detail in CPython.copy.deepcopy()
rather thandict()
ordict.copy()
. Imran's concise answer is on the right side of sanity, unlike this answer.