1

Maybe I don't understand the definition of shallow copy... but i'm very confused:

from the docs:

Where "s" is a list (but same question applies to dictionaries respectively).

"s.copy() | creates a shallow copy of s (same as s[:])"

Except I thought s[:] was a deep copy. For example, see this stack overflow answer on how to copy a list (without it just pointing to the original version). And using list1.copy() seems to do a deep copy as well aka same behaviour as [:]

l1 = [1,2,3,4]
l2 = l1[:]
l3 = l1.copy()



l2.append(5)
l3[0] = 99
print(l1)
print(l2)
print(l3)
>> [1,2,3,4]
>> [1,2,3,4,5]
>> [99,2,3,4]

It would appear that l1,l2, and l3 are all separate objects. What am I missing?

Community
  • 1
  • 1
RSHAP
  • 2,337
  • 3
  • 28
  • 39
  • ... if I change l1 to a list of lists of numbers i still get the same thing - l1.copy() seems to create a separate object – RSHAP May 15 '17 at 15:58
  • 1
    No. Those are both shallow copies. The distinction in that question is between mere assignment (which doesn't copy at all) and a copy (a shallow one) – juanpa.arrivillaga May 15 '17 at 15:58
  • @juanpa.arrivillaga, Ahhhh ok I see this answers it. – RSHAP May 15 '17 at 16:03
  • @RSHAP you can test for deep equality with `is` and for shallow with `==`. Here deep equality implies shallow equality. (`l1 is l2` is `True` only, if both references point to the same object, while `l1 == l2` is `True` when all values of `l1` and `l2` are equal) – Chris May 15 '17 at 16:03

2 Answers2

4

You've simply misunderstood what "shallow" and "deep" mean in this context.

A shallow copy is a copy of the top level of elements only. If any of those elements are themselves lists, the copies will still refer to the original lists. This is what both l1[:] and l1.copy() do.

A deep copy is a copy at all levels. If any of the elements are lists, they will also be deep copied. No references will be shared. This is what copy.deepcopy() does.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
2

A shallow copy means that the new list holds references to the same object that the old list has.

For example:

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

We'll see that mutations of objects in bar also "pollute" foo.

If we re-do this example using a deep copy, it's a different story:

import copy
foo = [1, 2, []]
bar = copy.deepcopy(foo)
bar[-1].append(3)
print(foo)

This is because the deep copy creates a new (deep copy) of the list instead of just copying over a reference to the old list.

mgilson
  • 300,191
  • 65
  • 633
  • 696