Chapters
Python114 chapters

CollectionsChapter 32 of 114

Copy Lists

Why assignment does not copy, and the difference between shallow and deep.

Assignment does not copy

This is the single most common list surprise. = gives the same list another name:

Python
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)
print(a is b)

Output

[1, 2, 3, 4]
[1, 2, 3, 4]
True

One list, two names. is confirms it.

Three ways to copy

All of these build a new list:

Python
original = [1, 2, 3]

by_slice = original[:]
by_method = original.copy()
by_call = list(original)

by_slice.append(99)
print(original)
print(by_slice, by_method, by_call)
print(by_slice is original)

Output

[1, 2, 3]
[1, 2, 3, 99] [1, 2, 3] [1, 2, 3]
False

copy() says what it means, so prefer it. [:] is common in older code, and list() is handy when you are converting something else anyway.

Shallow means one level deep

All three copy the outer list. The items inside are still shared, which only shows when those items are themselves changeable:

Python
grid = [[1, 2], [3, 4]]
shallow = grid.copy()

shallow[0].append(99)
print(grid)

Output

[[1, 2, 99], [3, 4]]

The outer lists are separate, but shallow[0] and grid[0] are the same inner list. Appending through one shows through the other.

Adding to the outer list behaves as you would expect:

Python
grid = [[1, 2]]
shallow = grid.copy()
shallow.append([5, 6])
print(grid)
print(shallow)

Output

[[1, 2]]
[[1, 2], [5, 6]]

deepcopy goes all the way down

Python
from copy import deepcopy

grid = [[1, 2], [3, 4]]
deep = deepcopy(grid)
deep[0].append(99)
print(grid)
print(deep)

Output

[[1, 2], [3, 4]]
[[1, 2, 99], [3, 4]]

deepcopy rebuilds every nested object, so nothing is shared. It costs more time and memory, so use it when you need it rather than by default.

When shallow is enough

If the items cannot be changed — numbers, strings, tuples — a shallow copy is a full copy for every practical purpose:

Python
names = ["Ada", "Grace"]
copy = names.copy()
copy[0] = "Alan"
print(names)
print(copy)

Output

['Ada', 'Grace']
['Alan', 'Grace']

Assigning to copy[0] replaces the item rather than changing it, so the original is untouched.

Copying is not always the answer

Often the cleanest fix is to build a new list rather than copy and edit one:

Python
prices = [10, 20, 30]
discounted = [p * 0.9 for p in prices]
print(prices)
print(discounted)

Output

[10, 20, 30]
[9.0, 18.0, 27.0]

Test yourself

2 questions

What does b = a do for a list a?

Show the answer

Gives the same list a second name — Use a.copy(), a[:] or list(a) to actually make a new list.

After shallow = grid.copy(), what does shallow[0].append(99) do to grid?

Show the answer

grid[0] gets 99 too, because the inner lists are shared — A shallow copy duplicates the outer list only. deepcopy rebuilds every level.

Next chapter

Join Lists

Put two lists together, and turn a list into a string.