I'm confused about how objects in shallow copy and deep copy are referenced

87 Views Asked by At

Shallow_Copy

foo = [1, 2, []] 
bar = foo.copy() 
foo[0] is bar[0] 
foo[2] is bar[2] 
True 
True 

Does this mean they both reference to the same objects? However, they behave differently when I modify them.

bar[0] = 0 
print(foo) 
[1, 2, []] 
bar[-1].append(3)
print(foo) 
[1, 2, [3]] 

if foo[0] and bar[0] are referencing the same object, when I modified bar[0] why did foo[0] stay the same? And when I modified bar[2], foo[2] changed

Deep_Copy

foo = [1, 2, []] 
bar = copy.deepcopy(foo)
foo[0] is bar[0] foo[2] is bar[2] 
True 
False 

Additionally, why foo[2] and bar[2] don't reference the same object here

2

There are 2 best solutions below

0
juanpa.arrivillaga On

The fundamental source of confusion here is which object are you actually mutating. The following line:

bar[0] = 0 

Mutates bar, not bar[0]. On the other hand,

bar[-1].append(3)

Mutates bar[-1], since .append is a mutator method.

But you would see the same behavior if you did the equivalent thing:

>>> foo = [1, 2, []]
>>> bar = foo.copy()
>>> foo[-1] = [3]
>>> foo, bar
([1, 2, [3]], [1, 2, []])
>>>
2
D.L On

In addition to the comments:

you can see the unique (identities) id's of the items with the id() method. "This is guaranteed to be unique among simultaneously existing objects".

So the code modified to this will be clearer:

foo = [1, 2, []] 
bar = foo.copy() 
print(foo[0] is bar[0]) 
print(foo[2] is bar[2]) 


print('foo id:', id(foo))
print('bar id:', id(bar))


print('bar[0] id:', id(bar[0]))

print('foo:', foo)

bar[-1].append(3)

print('bar:', bar)

which returns this:

True
True
foo id: 2526001813312
bar id: 2526001811840
bar[0] id: 140706948506408
foo: [1, 2, []]
bar: [1, 2, [3]]

In particular, you can now see that the id's are different. So they are in fact different objects.

So modifications to bar will not modify foo and visa versa.

For the deepcopy part, the code requires an import and a modification like this shows what is happening.

import copy
foo = [1, 2, []] 
bar = copy.deepcopy(foo)
print('foo:', foo)
print('bar:', bar)

print(foo[0] is bar[0]) 
print(foo[2] is bar[2])
print([] is []) 

which returns this:

foo: [1, 2, []]
bar: [1, 2, []]
True
False
False

bascially foo[2] and bar[2] are empty lists. we can see from print([] is []) that we get False.

Here is a link to the docs: https://docs.python.org/3/library/copy.html#copy.deepcopy