DEV Community

Samuel Ochaba
Samuel Ochaba

Posted on

The Python Matrix Gotcha That Silently Corrupts Your Data

Here's innocent-looking code to create a 2×3 matrix of zeros:

>>> row = [0, 0, 0]
>>> matrix = [row for _ in range(2)]
>>> matrix
[[0, 0, 0], [0, 0, 0]]
Enter fullscreen mode Exit fullscreen mode

Looks perfect. Now let's change one cell:

>>> matrix[0][0] = 99
>>> matrix
[[99, 0, 0], [99, 0, 0]]    # BOTH rows changed!
Enter fullscreen mode Exit fullscreen mode

We modified matrix[0][0], but matrix[1][0] changed too. What happened?

The Problem: Aliasing

When we wrote [row for _ in range(2)], we didn't create two rows. We created two references to the same row.

matrix[0] ──┐
            ├──► [99, 0, 0]  (same list object)
matrix[1] ──┘
Enter fullscreen mode Exit fullscreen mode

Every "row" in our matrix is the same object in memory. Change one, change all.

The Fix: Create New Lists

Each row must be a new list object:

>>> matrix = [[0, 0, 0] for _ in range(2)]
>>> matrix[0][0] = 99
>>> matrix
[[99, 0, 0], [0, 0, 0]]    # Only first row changed ✓
Enter fullscreen mode Exit fullscreen mode

Or more generally:

>>> rows, cols = 2, 3
>>> matrix = [[0 for _ in range(cols)] for _ in range(rows)]
Enter fullscreen mode Exit fullscreen mode

The inner comprehension [0 for _ in range(cols)] runs fresh for each row, creating a new list each time.

Why This Trips People Up

The original code reads correctly: "make a list of row, two times."

But in Python, row is a reference. Repeating a reference doesn't copy the underlying object—it just creates more pointers to it.

Quick Diagnostic

Suspicious your matrix has this bug? Check with is:

>>> bad_matrix = [row for _ in range(2)]
>>> bad_matrix[0] is bad_matrix[1]
True    # Same object! Bug confirmed.

>>> good_matrix = [[0, 0, 0] for _ in range(2)]
>>> good_matrix[0] is good_matrix[1]
False   # Different objects. Safe.
Enter fullscreen mode Exit fullscreen mode

The Rule

When creating nested structures with comprehensions:

Never repeat a reference. Always create fresh.

# WRONG - reuses same list
template = [0, 0, 0]
matrix = [template for _ in range(n)]

# RIGHT - creates new list each time
matrix = [[0, 0, 0] for _ in range(n)]
Enter fullscreen mode Exit fullscreen mode

This applies to lists of lists, lists of dicts, lists of any mutable object.


This is adapted from my upcoming book, Zero to AI Engineer: Python Foundations.
I share excerpts like this on Substack → https://substack.com/@samuelochaba

Top comments (0)