How to make a "deep copy" in Python?

Asked

Viewed 4,493 times

9

Let’s say I have the following code:

class Foo:
    pass


foo_list = [Foo() for _ in range(10)]

How can I proceed to create a copy of foo_list without the references of both the list and the objects contained therein being passed to the next list?

1 answer

15


What you’re doing is just one Shallow copy (surface copy).

DOCS:

The Difference between Shallow and deep copying is only Relevant for compound Objects (Objects that contain other Objects, like lists or class instances)

Translation:

The difference between superficial copy and deep copy is only relevant for composite objects, * is your case, (objects containing other objects objects such as lists or instances of classes)

deep copy (deep copy):

import copy

y = [[1,2,3], [4,5,6]]
x = copy.deepcopy(y)
x[0].append(10)

print(y) # [[1, 2, 3], [4, 5, 6]]
print(x) # [[1, 2, 3, 10], [4, 5, 6]]
print(id(y[0])) # 140313159068680
print(id(x[0])) # 140313158999816

Here, x and y, and all that belongs to them, are 'considered' different/independent objects, references to their internal objects are different and so it is possible to operate in each without affecting the other contained in the other list.

DEMONSTRATION

Shallow copy (superficial copy):

y = [[1,2,3], [4,5,6]]
x = y[:]
x[0].append(10)

print(y) # [[1, 2, 3, 10], [4, 5, 6]]
print(x) # [[1, 2, 3, 10], [4, 5, 6]]
print(id(y[0])) # 139853165128712
print(id(x[0])) # 139853165128712

Here, the internal objects of x and y have exactly the same references, and so share literally the same objects/values.

DEMONSTRATION

Using your example to demonstrate the differences:

from copy import deepcopy

class Foo: pass

foo = Foo()
foo.bar = 10

shallow_copies = [foo for _ in range(10)] # todos os foo partilham as mesmas referencias internas
deep_copies = [deepcopy(foo) for _ in range(10)] # copias independentes, referencias diferentes

shallow_copies[0].bar = 100 # mudar valor da propriedade do primeiro foo
deep_copies[0].bar = 100 # mudar valor da propriedade do primeiro foo

print([f.bar for f in shallow_copies]) # [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]
print([f.bar for f in deep_copies]) # [100, 10, 10, 10, 10, 10, 10, 10, 10, 10]
print(all(f.bar is shallow_copies[0].bar for f in shallow_copies[1:])) # True , todos os foo tem bar com a mesma ref
print(all(f.bar is deep_copies[0].bar for f in deep_copies[1:])) # False

Browser other questions tagged

You are not signed in. Login or sign up in order to post.