Copy a List in Python: Slicing, copy(), and deepcopy()

Quick answer: Assignment creates another reference to a list. Use slicing, list(), or copy() for a shallow copy of the outer list, and use copy.deepcopy only when nested mutable objects must be independent and the ownership and performance costs are understood.

Python Pool infographic comparing Python list aliasing, shallow copies, and deep copies across nested mutable values
A shallow list copy duplicates the outer container but keeps references to nested objects; choose deep copying only when the nested ownership contract requires it.

To copy a list in Python, use list.copy(), slicing, or list() for a shallow copy. Use copy.deepcopy() only when the list contains nested mutable objects and you need the nested objects copied too.

copied = original.copy()

Assignment does not copy a list

The = operator does not copy a list. It creates another name for the same list object. If you mutate the alias, the original changes too.

numbers = [1, 2, 3]
alias = numbers

alias.append(4)
print(numbers)

Output:

[1, 2, 3, 4]

Use assignment when you intentionally want two names pointing to the same list. Use a copy method when you want a separate list container.

Copy a list with list.copy()

list.copy() is the clearest way to make a shallow copy of a list in modern Python.

numbers = [1, 2, 3]
copied = numbers.copy()

copied.append(4)
print(numbers)
print(copied)

Output:

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

The copied list gets the appended value, while the original list remains unchanged.

Copy a list with slicing

Slicing the whole list with [:] creates the same kind of shallow copy. You will still see this pattern in many Python codebases.

numbers = [1, 2, 3]
copied = numbers[:]
print(copied)

Use numbers.copy() when readability matters most, and numbers[:] when you are already working with slices.

Python Pool infographic showing assignment binding two names to one mutable list and a shared mutation
List aliases: Assignment binding two names to one mutable list and a shared mutation.

Copy a list with list()

The list() constructor also creates a new list from an iterable. It is useful when the source might be another iterable, such as a tuple, generator, or dictionary view.

numbers = [1, 2, 3]
copied = list(numbers)
print(copied)

For an existing list, numbers.copy(), numbers[:], and list(numbers) all create a shallow copy.

Shallow copy vs deep copy

A shallow copy creates a new outer list, but it keeps references to the same nested objects. This matters for lists of lists.

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

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

Output:

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

The outer list is new, but the first inner list is shared. Mutating that inner list appears in both variables.

Copy nested lists with deepcopy()

Use copy.deepcopy() when you need independent nested lists.

from copy import deepcopy

matrix = [[1, 2], [3, 4]]
deep = deepcopy(matrix)

deep[0].append(99)
print(matrix)
print(deep)

Output:

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

deepcopy() recursively copies contained objects. It is the right tool for nested mutable data, but it can be slower and may copy more than you need for large object graphs.

Use list comprehension when changing values

If you want a transformed list, use a list comprehension instead of copying and then editing each item.

numbers = [1, 2, 3]
squares = [number ** 2 for number in numbers]
print(squares)

This creates a new list with squared values. The original list is not changed.

Python Pool infographic showing a new outer list retaining references to nested objects
Shallow list copy: A new outer list retaining references to nested objects.

Avoid repeated nested list traps

The multiplication operator can repeat references to the same nested list. Use a list comprehension when creating independent nested lists.

bad_grid = [[0] * 3] * 2
bad_grid[0][0] = 1
print(bad_grid)

good_grid = [[0] * 3 for _ in range(2)]
good_grid[0][0] = 1
print(good_grid)

The first grid shares the same inner list twice. The second grid creates a new inner list for each row. For more nested-list examples, see our Python 2D list guide.

Which method should you use?

  • old.copy(): best default for copying a normal list.
  • old[:]: fine for shallow copies, especially in slice-heavy code.
  • list(old): useful when the source may be any iterable.
  • deepcopy(old): use for nested mutable data that must be independent.
  • List comprehension: use when you want to transform values while building a new list.

Common mistakes

  • Using = and expecting a copy: assignment creates an alias, not a new list.
  • Expecting shallow copy to clone nested lists: shallow copy only copies the outer list container.
  • Using append() to copy one list into another: that nests the list. Use extend() or a copy method depending on the goal.
  • Using * for nested lists: [[0] * 3] * 2 repeats the same inner list reference.
  • Deep copying everything by default: deepcopy() is powerful, but unnecessary for simple flat lists.
Python Pool infographic showing nested graphs, cycles, memoized deepcopy, and ownership checks
Deep list copy: Nested graphs, cycles, memoized deepcopy, and ownership checks.

Related Python guides

Official references

Conclusion

Use my_list.copy() when you need a straightforward shallow copy of a list. Use slicing or list() when they fit the surrounding code, and switch to deepcopy() only when nested mutable objects must be copied independently.

Recognize Aliases

If two names point to the same list, append, remove, or item assignment through either name changes the same object. Check identity with is when diagnosing this behavior.

Make A Shallow Copy

list_value.copy(), list(list_value), and list_value[:] create a new outer list. Elements remain shared references, which is correct for immutable elements and sometimes intended for objects with shared ownership.

Handle Nested Lists

A shallow copy of [[1]] still shares the inner list. Mutating that nested value changes both outer lists, so copy the nested structure only when the data contract requires independent ownership.

Python Pool infographic choosing comprehension, slice, copy, or deepcopy by sharing and performance requirements
List copy ownership: Python Pool infographic choosing comprehension, slice, copy, or deepcopy by sharing and performance requirements.

Use Deepcopy Carefully

copy.deepcopy recursively copies supported objects and tracks cycles, but custom resources, locks, caches, file handles, and large graphs may not have meaningful or efficient deep-copy behavior.

Prefer Explicit Construction

For a known schema, a comprehension or constructor can copy exactly the fields needed and avoid copying accidental state. This is often clearer than a blanket deep copy.

Test Identity And Values

Test empty and nested lists, aliases, immutable elements, shallow changes, deep changes, custom objects, cycles, and performance before selecting the copy strategy.

Use the official Python copy documentation. Related Python Pool references include Python lists and testing.

For related collection semantics, compare list operations, nested mappings, and identity tests before copying state.

Frequently Asked Questions

How do I make a shallow copy of a Python list?

Use list_value.copy(), list(list_value), or list_value[:] when an independent outer list with shared element references is the intended result.

When should I use deepcopy?

Use copy.deepcopy when nested mutable objects must also be copied, after considering custom objects, resources, cycles, and the cost of recursive copying.

Why did changing the copied list change the original?

The variables may reference the same list, or a shallow copy may still share a nested list or dictionary.

Is assignment a list copy?

No. Assignment creates another reference to the same list; it does not create a new container.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted