Can someone please explain this to me? This doesn\'t make any sense to me.
I copy a dictionary into another and edit the second and both are changed. Why is this hap
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()
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.
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.
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).
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']]
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)