265

After E0_copy = list(E0), I guess E0_copy is a deep copy of E0 since id(E0) is not equal to id(E0_copy). Then I modify E0_copy in the loop, but why is E0 not the same after?

E0 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for k in range(3):
    E0_copy = list(E0)
    E0_copy[k][k] = 0
    #print(E0_copy)
print E0  # -> [[0, 2, 3], [4, 0, 6], [7, 8, 0]]
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Shen
  • 2,911
  • 3
  • 15
  • 10
  • 2
    Also, b = a[:] is a shallow copy. Refer http://stackoverflow.com/questions/16270374/how-to-make-a-shallow-copy-of-a-list-in-python – Arvind Haran Jul 26 '13 at 05:23

10 Answers10

378

E0_copy is not a deep copy. You don't make a deep copy using list(). (Both list(...) and testList[:] are shallow copies, as well as testList.copy().)

You use copy.deepcopy(...) for deep copying a list.

copy.deepcopy(x[, memo])

Return a deep copy of x.

See the following snippet -

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b   # b changes too -> Not a deepcopy.
[[1, 10, 3], [4, 5, 6]]

Now see the deepcopy operation

>>> import copy
>>> b = copy.deepcopy(a)
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]
>>> a[0][1] = 9
>>> a
[[1, 9, 3], [4, 5, 6]]
>>> b    # b doesn't change -> Deep Copy
[[1, 10, 3], [4, 5, 6]]

To explain, list(...) does not recursively make copies of the inner objects. It only makes a copy of the outermost list, while still referencing the same inner lists, hence, when you mutate the inner lists, the change is reflected in both the original list and the shallow copy. You can see that shallow copying references the inner lists by checking that id(a[0]) == id(b[0]) where b = list(a).

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Sukrit Kalra
  • 33,167
  • 7
  • 69
  • 71
  • list1.append(list2) is also a shallow copy of list2 – Lazik Dec 12 '13 at 13:56
  • 5
    Keep in mind that `copy.deepcopy` is [incredibly slow](https://stackoverflow.com/a/62865237/6243352) relative to list slicing (about 20x). [Implementing `__deepcopy__`](https://stackoverflow.com/a/15774013/6243352) in a class can help speed it up a bit. – ggorlen Sep 27 '20 at 19:55
  • @Lazik Eh? No it's not. Where did you get that from? Maybe you meant something like `list1 = []; list1.extend(list2)`? – wjandrea Dec 17 '21 at 20:08
  • I meant list1[0] will be a shallow copy of list2. You can check with id(list1[0]) – Lazik Feb 14 '22 at 14:16
  • @Lazik No, it's not a copy. To prove it, `list1 = []; list2 = [99]; list1.append(list2); list1[0] is list2` -> `True`. – wjandrea Apr 09 '23 at 18:14
  • @wjandrea "A shallow copy of an object is a copy whose properties share the same references (point to the same underlying values) as those of the source object from which the copy was made." -mozilla – Lazik Apr 11 '23 at 20:02
  • @Lazik But it's not a copy in the first place – wjandrea Apr 11 '23 at 21:09
  • @wjandrea It's called a shallow copy of list2 in list1. you can have a look at watashiSHUN's answer. – Lazik Apr 14 '23 at 13:25
97

In Python, there is a module called copy with two useful functions:

import copy
copy.copy()
copy.deepcopy()

copy() is a shallow copy function. If the given argument is a compound data structure, for instance a list, then Python will create another object of the same type (in this case, a new list) but for everything inside the old list, only their reference is copied. Think of it like:

newList = [elem for elem in oldlist]

Intuitively, we could assume that deepcopy() would follow the same paradigm, and the only difference is that for each elem we will recursively call deepcopy, (just like mbguy's answer)

but this is wrong!

deepcopy() actually preserves the graphical structure of the original compound data:

a = [1,2]
b = [a,a] # there's only 1 object a
c = deepcopy(b)

# check the result
c[0] is a # False, a new object a_1 is created
c[0] is c[1] # True, c is [a_1, a_1] not [a_1, a_2]

This is the tricky part: during the process of deepcopy(), a hashtable (dictionary in Python) is used to map each old object ref onto each new object ref, which prevents unnecessary duplicates and thus preserves the structure of the copied compound data.

Official docs

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
watashiSHUN
  • 9,684
  • 4
  • 36
  • 44
  • 5
    The deepcopy docs should be updated to prominently include the warning/example at the end of this answer. – proximous Oct 24 '20 at 17:50
  • It has to work this way to be general-purpose, because otherwise it would get into an unbound loop or recursion trying to process a cycle. – Karl Knechtel Jul 08 '22 at 21:06
26

If the contents of the list are primitive data types, you can use a comprehension

new_list = [i for i in old_list]

You can nest it for multidimensional lists like:

new_grid = [[i for i in row] for row in grid]
aljgom
  • 7,879
  • 3
  • 33
  • 28
14

@Sukrit Kalra

No.1: list(), [:], copy.copy() are all shallow copy. If an object is compound, they are all not suitable. You need to use copy.deepcopy().

No.2: b = a directly, a and b have the same reference, changing a is even as changing b.

set a to b

if assgin a to b directly, a and b share one reference.

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[1, [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]

shadow copy

by list()

list() and [:] are the same. Except for the first layer changes, all other layers' changes will be transferred.

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]

by [:]

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]

list() and [:] change the other layers, except for the 1st layer

# =========== [:] ===========
>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2] = 4
>>> a
[[1, 2, 4], [4, 5, 6]]
>>> b
[[1, 2, 4], [4, 5, 6]]


>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2][0] = 999
>>> a
[[1, 2, [999, 6]], [4, 5, 6]]
>>> b
[[1, 2, [999, 6]], [4, 5, 6]]



# =========== list() ===========
>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2] = 4
>>> a
[[1, 2, 4], [4, 5, 6]]
>>> b
[[1, 2, 4], [4, 5, 6]]


>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2][0] = 999
>>> a
[[1, 2, [999, 6]], [4, 5, 6]]
>>> b
[[1, 2, [999, 6]], [4, 5, 6]]

by copy()

You will find that copy() function is the same as list() and [:]. They are all shallow copy.

For much more information about shallow copy and deep copy, maybe you can reference here.

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.copy(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]

by deepcopy()

>>> import copy
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.deepcopy(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.deepcopy(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]

Mystic
  • 310
  • 4
  • 14
  • Please [edit] your answer to include an explanation of how this works and why it is of solution to the problem described in the question. See [answer]. – Gander Dec 16 '20 at 01:52
  • [Here is the much more detailed case](https://blog.caoyu.info/copy-list-python.html) – Mystic Jan 22 '21 at 08:51
8

If your list elements are immutable objects then you can use this, otherwise you have to use deepcopy from copy module.

you can also use shortest way for deep copy a list like this.

a = [0,1,2,3,4,5,6,7,8,9,10]
b = a[:] #deep copying the list a and assigning it to b
print id(a)
20983280
print id(b)
12967208

a[2] = 20
print a
[0, 1, 20, 3, 4, 5, 6, 7, 8, 9,10]
print b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10]
wjandrea
  • 28,235
  • 9
  • 60
  • 81
tailor_raj
  • 1,037
  • 2
  • 9
  • 19
  • 32
    This is not a Deep Copy. – Sukrit Kalra Jul 26 '13 at 06:31
  • 1
    Then what is it. It has two different dictionaries (you can check the id's of each one) with same values. – tailor_raj Jul 26 '13 at 06:32
  • 2
    Read [this](http://docs.python.org/2/library/copy.html), [:] just creates a shallow copy, it does not recursively create copies of the objects inside one. – Sukrit Kalra Jul 26 '13 at 06:35
  • 1
    Thanks. you mean to say if we use this, new list will be created but all elements of new list will be copies only, they will be having same object (same id) as of previous one ? – tailor_raj Jul 26 '13 at 06:40
  • 2
    Try using a nested list. Update the nested item of the list a. It'll get updated in list b too. This implies a[:] isn't deep copy. – AnupamChugh Apr 10 '20 at 13:25
  • 2
    [Python documentation](https://docs.python.org/3.7/tutorial/datastructures.html) (see `list.copy()`) explicitly describes `a[:]` as a way to perform a shallow copy. – Mark Jun 16 '20 at 06:45
  • 1
    This solutions works only when we don't have nested lists, in case of nested list, it will be a shallow copy. – Priyanshu Tiwari Feb 18 '22 at 23:00
1

Here's an example of how to deep copy a 2D list:

  b = [x[:] for x in a]
AnupamChugh
  • 1,779
  • 1
  • 25
  • 36
  • 1
    Did you test this example? `a = [3, 4, 5] b = [x[:] for x in a] Traceback (most recent call last): File "", line 1, in File "", line 1, in TypeError: 'int' object is not subscriptable` – Stef Sep 08 '20 at 08:34
  • Ah, I wrote that for 2D lists. a = [[0,1],[2,3]]. I've edited the answer to highlight this. – AnupamChugh Sep 09 '20 at 06:47
  • @AnupamChugh, this is not a deep copy. – user2987828 Feb 14 '22 at 07:27
0

If you are not allowed to directly import modules you can define your own deepcopy function as -

def copyList(L):
if type(L[0]) != list:
    return [i for i in L]
else:
    return [copyList(L[i]) for i in range(len(L))]

It's working can be seen easily as -

>>> x = [[1,2,3],[3,4]]
>>> z = copyList(x)
>>> x
[[1, 2, 3], [3, 4]]
>>> z
[[1, 2, 3], [3, 4]]
>>> id(x)
2095053718720
>>> id(z)
2095053718528
>>> id(x[0])
2095058990144
>>> id(z[0])
2095058992192
>>>
0

If you are assigning to the same list using deepcopy, use a temporary variable instead. For some reason, copy.deepcopy() does not work on object lists when trying to self update same variable using indexing

S = S[idx] ->x
S = copy.deepcopy(S[idx])  -> x

vvvv although this worked

Stemp = np.zeros(N,dtype=object)
for ii in range(N):
   Stemp[ii]=copy.deepcopy(S[idx[ii]])
S= copy.deepcopy(Stemp)
Ajinkya
  • 1
  • 1
-1

just a recursive deep copy function.

def deepcopy(A):
    rt = []
    for elem in A:
        if isinstance(elem,list):
            rt.append(deepcopy(elem))
        else:
            rt.append(elem)
    return rt

Edit: As Cfreak mentioned, this is already implemented in copy module.

rnbguy
  • 1,369
  • 1
  • 10
  • 28
-1

Regarding the list as a tree, the deep_copy in python can be most compactly written as

def deep_copy(x):
    if not isinstance(x, list):
        return x
    else:
        return [deep_copy(elem) for elem in x]

It's basically recursively traversing the list in a depth-first way.

ShellayLee
  • 327
  • 2
  • 6