The difference between copying and referencing a matrix

When you assign a matrix to a new variable in Python, you are not creating a separate copy — you are creating a second name for the same object in memory. If you change a value in one variable, the other changes too, because they point to the same data. To create an actual copy that you can modify without affecting the original, you need to use one of Python's copy methods.

This matters because many beginners expect assignment to work like copying. You write matrix_copy = matrix_original and assume you now have two independent matrices. In reality, both variables refer to the same underlying list or array, so modifying one modifies the other.

Key Takeaways

  • Assignment with = creates a reference to the same matrix, not a copy, so changes to one affect the other.
  • Use copy.deepcopy() for nested lists (lists of lists) to copy all layers and avoid shared references.
  • Use .copy() method or numpy.copy() for NumPy arrays to create independent copies.
  • A shallow copy with copy.copy() or slicing creates a new outer list but inner lists still reference the original, which breaks with nested structures.

Copying a matrix made from nested lists

If your matrix is a list of lists (the most common way to represent a matrix without external libraries), you need copy.deepcopy() from Python's built-in copy module. This copies every layer of nesting, so the new matrix is completely independent.

Here is the code:

import copy matrix_original = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] matrix_copy = copy.deepcopy(matrix_original) matrix_copy[0][0] = 99 print(matrix_original) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]] print(matrix_copy) # [[99, 2, 3], [4, 5, 6], [7, 8, 9]]

The original matrix stays unchanged because deepcopy() creates new inner lists as well as a new outer list. Without deepcopy, a shallow copy would create a new outer list but the inner lists would still point to the original, so changing matrix_copy[0][0] would also change matrix_original[0][0].

Copying a NumPy array

If you are working with NumPy (the standard library for numerical computing in Python), use the .copy() method on the array object. This is simpler and faster than deepcopy for arrays.

Here is the code:

import numpy as np matrix_original = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) matrix_copy = matrix_original.copy() matrix_copy[0][0] = 99 print(matrix_original) # [[1 2 3] [4 5 6] [7 8 9]] print(matrix_copy) # [[99 2 3] [4 5 6] [7 8 9]]

You can also use numpy.copy() as a function instead of a method, which does the same thing. The .copy() method is more common and slightly more readable.

Why slicing does not create a true copy

A common mistake is using slicing to copy a matrix. For a single list, matrix_copy = matrix_original[:] creates a new list. But for a matrix (a list of lists), this only copies the outer list — the inner lists still reference the original.

Here is what goes wrong:

matrix_original = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] matrix_copy = matrix_original[:] # Shallow copy matrix_copy[0][0] = 99 print(matrix_original) # [[99, 2, 3], [4, 5, 6], [7, 8, 9]] — changed!

The inner list [1, 2, 3] is the same object in both matrices, so modifying it through one variable modifies it for both. Use deepcopy() instead to avoid this trap.

Copying specific rows or columns

Sometimes you only need to copy part of a matrix. With NumPy, slicing creates a view (a reference to the original data), not a copy. To copy a slice, call .copy() on the slice itself.

Here is the code:

import numpy as np matrix_original = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # This is a view, not a copy row_view = matrix_original[0] # This is a true copy row_copy = matrix_original[0].copy() row_copy[0] = 99 print(matrix_original[0]) # [1 2 3] — unchanged

With nested lists, extract the row or column you want and then deepcopy it if you need to modify it without affecting the original.

Performance considerations when choosing a copy method

For small matrices, the performance difference between methods is negligible. For large matrices, .copy() on a NumPy array is much faster than deepcopy() on nested lists, because NumPy is optimized for numerical operations and uses compiled C code underneath.

If you are working with matrices larger than a few hundred rows and columns, use NumPy. If you are working with small matrices or matrices with mixed data types (numbers, strings, objects), nested lists with deepcopy() are fine. NumPy also uses less memory for large numerical matrices, so it is the better choice for data-heavy work.

Frequently Asked Questions

What happens if I just use = to assign a matrix to a new variable?

Both variables point to the same matrix in memory. Any change to one is visible in the other. This is called a reference, not a copy. Use copy.deepcopy() for nested lists or .copy() for NumPy arrays to create an independent copy.

Can I use copy.copy() instead of copy.deepcopy() for a matrix?

No. copy.copy() creates a shallow copy, which copies only the outer list. The inner lists still reference the original, so modifying inner values affects both matrices. Always use deepcopy() for nested lists.

Does slicing a NumPy array create a copy?

No, slicing creates a view — a reference to the original data. To copy a slice, call .copy() on the slice: matrix_copy = matrix_original[0:2].copy(). This is especially important if you plan to modify the slice.

Which method is fastest for large matrices?

NumPy's .copy() method is much faster than deepcopy() on nested lists, especially for matrices with thousands of elements. If performance matters, use NumPy arrays instead of nested lists.