Copying, References, and Mutable Objects
This type of problem appears very frequently in the early stages of learning Python: why does original_list change when I modify new_list?
The reason is usually not "lists are weird" but that you got a reference to the same object.
Assignment is not a copy
original = [1, 2, 3]
new_list = original
new_list.append(4)
print(original) # [1, 2, 3, 4]
print(new_list) # [1, 2, 3, 4]
new_list = original doesn't copy the list; it makes both variables point to the same list object.
Shallow Copy
The following approaches all create a new outer list:
items = [1, 2, 3]
a = items[:]
b = list(items)
c = items.copy()
But they only copy one level
items = [[1, 2], [3, 4]]
copied = items.copy()
copied[0].append(99)
print(items) # [[1, 2, 99], [3, 4]]
print(copied) # [[1, 2, 99], [3, 4]]
Because although the outer list is new, the nested sub-lists inside still point to the same objects.
Deep Copy
If the object has nested structures inside, consider copy.deepcopy():
import copy
items = [[1, 2], [3, 4]]
copied = copy.deepcopy(items)
copied[0].append(99)
print(items) # [[1, 2], [3, 4]]
print(copied) # [[1, 2, 99], [3, 4]]
Why this matters
Because many objects in Python are mutable:
listdictset
If you haven't distinguished "am I modifying the original" from "am I modifying a copy", debugging later will be very painful.
My own decision process
- Only wrote
a = b: basically not a copy - Only copied the outermost layer: shallow copy
- There's nesting inside, and you want complete independence: deep copy