3

Does list make a shallow copy or deep copy in Python 3? I wrote the following code to see:

X = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Y = list(X)  # Makes a shallow copy
X.append([3445])
print(Y)
print(X)
X[0][1]="asddasdsaa"
print(Y)
print(X)

The output:

[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [3445]]
[[1, 'asddasdsaa', 3], [4, 5, 6], [7, 8, 9]]
[[1, 'asddasdsaa', 3], [4, 5, 6], [7, 8, 9], [3445]]

Its seems that list is a shallow copy.

Same code with a simple list:

X = [1,23,22]
Y = list(X) # Seems like deep copy
X.append(334)
print(Y)
print(X)
X[0]=222
print(Y)
print(X)

The output:

[1, 23, 22]
[1, 23, 22, 334]
[1, 23, 22]
[222, 23, 22, 334]

This seems like a deep copy. I am confused.

KAY_YAK
  • 191
  • 10
  • 2
    What part of the second snippet seems like a deep copy? – user2357112 Jan 11 '19 at 08:09
  • I guess when the OP tried to alter an element, it didn't reflect in the copy. – Nitin Pawar Jan 11 '19 at 08:10
  • 5
    The second example is a list of *immutable* objects, integers, so you can't tell whether it's deep or shallow from that. – jonrsharpe Jan 11 '19 at 08:10
  • Deep copying is an *expensive* operation that is only needed when using nested *mutable* structures. It slows down even non-nested copy (since you have to check if the elements should be deep copied or not). Having it as a default behaviour for anything means a big slow down for most programs. So *obviously* anything that does not have `deep` in its method name or a parameter like `deep=True` does not do a deep copy. Then third parties can write bad code as you like... – Giacomo Alzetta Jan 11 '19 at 08:15
  • Possible duplicate of [What exactly is the difference between shallow copy, deepcopy and normal assignment operation?](https://stackoverflow.com/questions/17246693/what-exactly-is-the-difference-between-shallow-copy-deepcopy-and-normal-assignm) – mkrieger1 Jan 11 '19 at 10:02

3 Answers3

2

@user2357112 is right, really, what part makes you thing that is a deep copy?

Actually @jonrsharpe is also right.

all copy ways, see below, are shallow copies:

l=l.copy()
l=l[:]
l=list(l)
...

Only copy.deepcopy is a deep copy:

from copy import deepcopy
l=deepcopy(l)
U13-Forward
  • 69,221
  • 14
  • 89
  • 114
  • So, list() is a shallow copy. Before X[0] = 222, both X and Y were referring to the same part [1,2,3,_] except Y[3] is not defined but X[3] is. Now, 1 is a literal and immutable. So after X[0] = 222, how is memory managed ? is there two list now [1,2,3] and [222, 23, 22, 334] ? – KAY_YAK Jan 11 '19 at 08:38
  • @KAY_YAK Yup, since there different `id`. – U13-Forward Jan 11 '19 at 08:40
1

In python, anything except int, float, bool, string, unicode & tuple is mutable.

As you can see list is mutable. The first example is updating/mutating an list in "list of lists" whereas in second example you are just trying to update a "list of ints" (immutable objects), as int is immutable, it is hard copied by default. Also, hard copying is expensive in nature.

BlackBeard
  • 10,246
  • 7
  • 52
  • 62
  • 1
    That fly. That's what I was guessing though. Also, when dealing with a list of mutable, I should be careful and use deep copy. – KAY_YAK Jan 11 '19 at 08:45
0

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

X = [1,23,22]
Y = list(X) # Seems like deep copy
X.append(334)
print(Y)
print(X)
X[0]=222
print(Y)
print(X)

This case has no compound object,so deep copy and copy are no difference.
ACE Fly
  • 305
  • 2
  • 8