How to make a "deep copy" in Python?

7

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 references to both the list and the objects contained therein being passed to the next list?

    
asked by anonymous 19.10.2017 / 20:38

1 answer

10

What you're doing is just a shallow copy shallow) .

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 shallow copy and deep copy is only relevant   for compound objects, * is your case , (objects that contain others   objects, such as lists or instances of classes)

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 everything that belongs to them, are 'considered' different / independent objects, references to their internal objects are different and so it is possible to operate on each one without affecting the other contained in the other list.

DEMONSTRATION

shallow 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, so they literally share 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
    
19.10.2017 / 22:19