Copy Lists
Learn every way to copy a Python list: assignment trap, slicing, copy(), list(), and deepcopy() — with runnable examples and clear explanations.
Python lists are mutable, which means assigning a list to a new variable does not create a copy — both names point to the same object. This page explains every reliable way to copy a list, the difference between a shallow copy and a deep copy, and when each approach is the right choice.
The Assignment Trap
A common mistake is using the = operator expecting it to produce an independent copy:
Why the = operator does not copy a list
Both original and alias point to the exact same list object in memory. Any change made through one name is immediately visible through the other.
To get a true independent copy, use one of the methods below.
Shallow Copy Methods
A shallow copy creates a new list object, but the elements inside the new list are still references to the same objects as the original. For a flat list (a list containing only immutable values like numbers and strings), a shallow copy behaves like a full independent copy.
Using the copy() Method
The copy() method is the most explicit and readable approach:
Copy a list with the copy() method
original = ["apple", "banana", "cherry"]
copy_of = original.copy()
copy_of.append("date")
print(original) # Output: ['apple', 'banana', 'cherry']
print(copy_of) # Output: ['apple', 'banana', 'cherry', 'date']The two lists are now independent: appending to copy_of does not affect original.
Using Slice Notation [:]
Slice notation is a Pythonic shorthand for copying the entire list:
Copy a list with slice notation
original = [10, 20, 30, 40]
copy_of = original[:]
copy_of[0] = 99
print(original) # Output: [10, 20, 30, 40]
print(copy_of) # Output: [99, 20, 30, 40][:] reads as "take every element from start to end," which produces a new list containing those elements.
Using the list() Constructor
Passing an existing list to list() also creates a shallow copy:
Copy a list with the list() constructor
original = [1, 2, 3]
copy_of = list(original)
copy_of.append(4)
print(original) # Output: [1, 2, 3]
print(copy_of) # Output: [1, 2, 3, 4]This is especially useful when converting another iterable (such as a tuple) to a list at the same time.
When Shallow Copies Are Not Enough
A shallow copy only copies the top-level structure. If the list contains mutable objects such as other lists or dictionaries, those nested objects are still shared between the original and the copy.
Shallow copy with a nested list
Both lists share the same inner list objects [1, 2] and [3, 4]. Changing original[0][0] modifies that shared inner list, so the change shows up in shallow as well.
Deep Copy
A deep copy recursively copies every object inside the list, producing a structure that is completely independent of the original. Use copy.deepcopy() from the standard library copy module:
Deep copy a nested list with copy.deepcopy()
import copy
original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original)
original[0][0] = 99 # Mutate the nested list
print(original) # Output: [[99, 2], [3, 4]]
print(deep) # Output: [[1, 2], [3, 4]] <- unchangeddeep holds its own copies of the inner lists, so changes to original do not affect it at all.
Shallow Copy vs. Deep Copy at a Glance
| Method | Creates new list? | Copies nested objects? | Best for |
|---|---|---|---|
= assignment | No | No | Aliases only |
copy() | Yes | No (shallow) | Flat lists |
[:] slicing | Yes | No (shallow) | Flat lists |
list() | Yes | No (shallow) | Flat lists / iterables |
copy.deepcopy() | Yes | Yes | Nested structures |
Practical Examples
Combining All Shallow Copy Methods
original = [1, 2, 3]
a = original.copy() # method
b = original[:] # slice
c = list(original) # constructor
original.append(4)
print(a) # Output: [1, 2, 3]
print(b) # Output: [1, 2, 3]
print(c) # Output: [1, 2, 3]All three produce independent copies — none of them reflects the later append(4).
Copying a List of Dictionaries
Dictionaries are mutable objects. A shallow copy of a list of dictionaries shares those dict objects:
import copy
records = [{"name": "Alice", "score": 90}, {"name": "Bob", "score": 85}]
shallow = records.copy()
deep = copy.deepcopy(records)
records[0]["score"] = 0
print(shallow[0]) # Output: {'name': 'Alice', 'score': 0} <- shared dict
print(deep[0]) # Output: {'name': 'Alice', 'score': 90} <- independent copyWhen the elements are mutable objects and you need full independence, always use deepcopy().
Conclusion
Python lists are mutable, so the = operator creates an alias, not a copy. For flat lists, any of the shallow copy methods — copy(), [:], or list() — work equally well. When lists contain nested mutable objects, use copy.deepcopy() to ensure full independence.
To explore related list operations, see List Methods, Add List Items, and Remove List Items. For copying dictionaries, the same shallow/deep distinction applies — see Copy Dictionaries.