Is it possible to copy an object in Python without copying a reference?
For example, if I define a class
class SomeClass: def __init__(self): self.value = 0and then create an instance
someObject = SomeClass()
someObject.value = 12and I try to copy it to another instance:
anotherObject = someObjectand try to modify a property,
anotherObject.value = 10the original property gets modified:
print someObject.value #prints 10Is there any way to prevent this from happening? To clarify, I want the anotherObject.value to contain 10, but I want someObject.value to still contain the original 12. Is this possible in python?
Thanks in advance.
5 Answers
The problem is, with
anotherObject = someObjectyou don't copy the object, but just add another reference to it. To copy an object, try this:
from copy import copy
anotherObject = copy(someObject) 1 import copy
obj2 = copy.deepcopy(obj2) 1 As you've noticed, anotherObject = someObject doesn't make a copy - if you want a copy, try
import copy
otherObject = copy.copy(someObject)The copy.copy vs copy.deepcopy distinction is important here - you can get away with copy.copy for the simple object you've described, but a more nested object would require copy.deepcopy.
copy.copy(someObject) makes a copy only of the object someObject, but if someObject contains references to other objects that can be changed ("mutable" objects) as in
someObject.value.this_one_has_values_too = 4or
someObject.value[0] = 1or
someObject.value['key'] = 'value'then references to those objects will be made in the copy. If you use copy.deepcopy, they'll also be copied over.
A great way to gain an understanding of this is playing with the Online Python Tutor (see linked example) but here's a straightforward demonstration of the behavior without the useful diagraming Online Python Tutor provides.
>>> import copy
>>> class Foo(object):
... pass
...
>>> f = Foo()
>>> f.value = 1
>>> f.nested_value = [2,3,4]
>>> deep = copy.deepcopy(f)
>>> deep.value = 5
>>> f.value
1
>>> deep.nested_value.append(6)
>>> f.nested_value
[2, 3, 4]
>>> shallow = copy.copy(f)
>>> shallow.value = 7
>>> f.value
1
>>> shallow.nested_value.append(8)
>>> f.nested_value
[2, 3, 4, 8]Edit: But what about the integer in the first example? It's actually being shared between the f object and the shallow object, but that's not a problem - it's not editable; we can't change an integer object like 1 to be any different, so we might as well save memory and use that one object anytime any Python object needs a reference to 1.
The thing to read about this is Ned's Facts and Myths about Python names and values.
6import copyIn some cases just:
copy_obj = copy.copy(obj)is enough but in other cases you should use:
copy_obj = copy.deepcopy(obj) 1 You can use copy for that. Try the following:
someObject = SomeClass()
someObject.value = 12
anotherObject = copy.copy(someObject)
anotherObject.value = 10Now someObject.value will still be 12. You will have to place import copy at the top of your script though.