The problem
When you copy a list containing other lists, a simple assignment doesn't create a true copy—both variables point to the same object. This can cause unexpected changes.
original = [[1, 2, 3], [4, 5, 6]]
copy = original # ❌ Not a copy!
copy[0][0] = 99
print(original) # [[99, 2, 3], [4, 5, 6]] — changed!
print(copy) # [[99, 2, 3], [4, 5, 6]]
Shallow copy (.copy())
A shallow copy creates a new object, but nested objects are still shared:
import copy
original = [[1, 2, 3], [4, 5, 6]]
shallow = original.copy() # or copy.copy(original)
# Modify nested list:
shallow[0][0] = 99
print(original) # [[99, 2, 3], [4, 5, 6]] — changed!
print(shallow) # [[99, 2, 3], [4, 5, 6]]
The outer list is new, but the inner lists are still the same objects.
Deep copy (deepcopy())
A deep copy creates completely independent copies of all nested objects:
import copy
original = [[1, 2, 3], [4, 5, 6]]
deep = copy.deepcopy(original)
# Modify nested list:
deep[0][0] = 99
print(original) # [[1, 2, 3], [4, 5, 6]] — unchanged!
print(deep) # [[99, 2, 3], [4, 5, 6]]
Now both the outer list and all nested lists are completely independent.
For simple (flat) lists
For lists without nested structures, shallow copy works fine:
original = [1, 2, 3]
copy = original.copy() # or list(original) or original[:]
copy[0] = 99
print(original) # [1, 2, 3] — unchanged
print(copy) # [99, 2, 3]
When to use each
- Shallow copy (
.copy()): When nested objects are immutable (like strings, numbers) or you want to share nested data - Deep copy (
deepcopy()): When you need completely independent copies of nested mutable objects (lists, dicts, etc.)
Other ways to copy
# For lists:
new_list = old_list.copy() # Method
new_list = list(old_list) # Constructor
new_list = old_list[:] # Slicing
# For dictionaries:
new_dict = old_dict.copy() # Method
new_dict = dict(old_dict) # Constructor
# For nested structures:
import copy
new = copy.deepcopy(old) # Always use deepcopy
Summary
- Assignment (
=): No copy, just another name for the same object - Shallow copy: New outer object, but nested objects are shared
- Deep copy: Completely independent copy of everything