Python prevent copying object as reference

Question:

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 = 0

and then create an instance

someObject = SomeClass()
someObject.value = 12

and I try to copy it to another instance:

anotherObject = someObject

and try to modify a property,

anotherObject.value = 10

the original property gets modified:

print someObject.value #prints 10

Is 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.

Asked By: Raghav Malik

||

Answers:

The problem is, with

anotherObject = someObject

you 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)
Answered By: Constantinius
import copy

obj2 = copy.deepcopy(obj2)
Answered By: Steve Barnes

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 = 4

or

someObject.value[0] = 1

or

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.

Answered By: Thomas

You can use copy for that. Try the following:

someObject = SomeClass()
someObject.value = 12
anotherObject = copy.copy(someObject)
anotherObject.value = 10

Now someObject.value will still be 12. You will have to place import copy at the top of your script though.

Answered By: Patrick Kostjens
import copy

In some cases just:

copy_obj = copy.copy(obj)

is enough but in other cases you should use:

copy_obj = copy.deepcopy(obj)
Answered By: Juba Fourali
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.