-1

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

Aaron
  • 25
  • 4
  • Have you read: https://stackoverflow.com/questions/17246693/what-is-the-difference-between-shallow-copy-deepcopy-and-normal-assignment-oper ? – srn Jun 21 '23 at 16:32
  • @jonrsharpe Thanks for the answer. For the second question, I guess I'm more confused because foo[0] and bar[0] still reference to the same object even when using deep copy – Aaron Jun 21 '23 at 17:16
  • @Aaron There's no need to create a new object for an integer. The value is not mutable so it will never change. – Matthias Jun 21 '23 at 17:26

2 Answers2

1

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, []])
>>>
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
0

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

D.L
  • 4,339
  • 5
  • 22
  • 45
  • I'm not really sure what this demonstrates that wasn't already clear from using `foo[0] is bar[0]` etc – juanpa.arrivillaga Jun 21 '23 at 20:31
  • @juanpa.arrivillaga, because this breaks the code down for the OP [1] to see the difference in the memory addresses and then [2] also a fundamental usage error and explanation for the deep copy... – D.L Jun 22 '23 at 07:59