Most Python developers are comfortable with basic list comprehensions. But as soon as you add a second pair of brackets [[]], things get scary.
Nested list comprehensions are the standard "Pythonic" way to work with matrices and 2D data grids. Whether you are building a tic-tac-toe board, processing image pixels, or handling data tables, you need to master this syntax.
In this guide, we will visualize exactly how Python processes nested loops so you can write them without getting a headache.
Table of Contents
- The Matrix Visualization
- Syntax Anatomy (Outer vs Inner)
- Creating Matrices (Initialization)
- The Reference Bug (Why you NEED comprehensions)
- Transposing a Matrix
- Iterating through 2D Lists
- Flattening vs Nesting
- FAQ
- Test Your Knowledge (Quiz)
The Matrix Visualization
Think of a nested list as a "List of Lists".
Row 0: [ 1, 2, 3 ]
Row 1: [ 4, 5, 6 ]
Row 2: [ 7, 8, 9 ]
If you want to create this structure, you need two loops:
- Outer Loop: Creates the rows (the containers).
- Inner Loop: Fills the rows (the numbers).
Syntax Anatomy
# [ [Inner] for item in Outer ]
[ [InnerExpression for item in InnerIterable] for item in OuterIterable ]
Key Insight: The loop closest to the very end is the Outer Loop.
Let's trace the execution order:
- Start Outer Loop: Pick first item.
- Run Inner Comprehension: Create a full list.
- Append: Add that list to the outer list.
- Repeat Outer Loop.
Creating Matrices (Initialization)
1. The Zero Matrix
Create a 3x3 grid filled with zeros.
grid = [[0 for col in range(3)] for row in range(3)]
# Result:
# [[0, 0, 0],
# [0, 0, 0],
# [0, 0, 0]]
2. The Identity Matrix
Create a diagonal of 1s.
identity = [[1 if r == c else 0 for c in range(3)] for r in range(3)]
# Result:
# [[1, 0, 0],
# [0, 1, 0],
# [0, 0, 1]]
3. The Number Grid
grid = [[r + c for c in range(3)] for r in range(3)]
# Result:
# [[0, 1, 2],
# [1, 2, 3],
# [2, 3, 4]]
The Reference Bug (Why you NEED comprehensions)
Beginners often try this shortcut to create a matrix:
# WRONG WAY
row = [0, 0, 0]
matrix = [row] * 3
# Result looks correct: [[0,0,0], [0,0,0], [0,0,0]]
The Trap: It isn't 3 separate lists. It is 3 references to the SAME list.
matrix[0][0] = 99
print(matrix)
# Result: [[99,0,0], [99,0,0], [99,0,0]]
# It changed ALL rows at once!
The Fix: Using a list comprehension ensures a new independent list is created in memory for every iteration of the outer loop.
# CORRECT WAY
matrix = [[0 for _ in range(3)] for _ in range(3)]
matrix[0][0] = 99
# Result: [[99,0,0], [0,0,0], [0,0,0]] (Safe)
Transposing a Matrix
Transposing means swapping rows and columns. This is a classic interview question.
Logic: The element at row[0] in every row becomes the new col[0].
matrix = [[1, 2], [3, 4], [5, 6]]
# 3 Rows, 2 Columns
transposed = [[row[i] for row in matrix] for i in range(2)]
# 2 Rows, 3 Columns
# Result: [[1, 3, 5], [2, 4, 6]]
Explanation:
for i in range(2): We loop 2 times (for the 2 columns).[row[i] for row in matrix]: For each column indexi, grab that element from every row.
Iterating through 2D Lists
Instead of creating a new matrix, sometimes you just want to modify an existing one.
Task: Multiply valid data > 10 by 2.
data = [[5, 12], [20, 8]]
processed = [[x * 2 if x > 10 else x for x in row] for row in data]
# Result: [[5, 24], [40, 8]]
Notice we preserved the 2D structure. If we wanted a 1D list, we would use flattening syntax.
Flattening vs Nesting
It is crucial to distinguish these two patterns.
1. Nesting (Preserving Structure) Brackets inside brackets.
[[x for x in inner] for inner in outer]
2. Flattening (removing Structure) No inner brackets. Multiple loops in one line.
[x for inner in outer for x in inner]
If you want to learn how to squash lists flat, check our next guide.
FAQ
Q1: Can I make 3D (Tensor) lists?
A: Yes. [[[k for k in range(3)] for j in range(3)] for i in range(3)]. But please don't. It is incredibly hard to read.
Q2: Is this faster than NumPy?
A: No. If you are doing heavy matrix math, use the NumPy library. Python lists are general-purpose containers; NumPy arrays are optimized memory blocks for math.
Q3: How do I handle rows of different lengths (Jagged Arrays)?
A: List comprehensions handle jagged arrays naturally because for x in row simply iterates however many items are in that specific row.
Test Your Knowledge
Conclusion
Nested list comprehensions are the only safe way to initialize matrices in Python. Mastering this pattern prevents the deadly "Reference Bug" and allows you to manipulate grid data with elegance.
Next Steps:
- Learn the opposite operation: Flattening Lists
- Explore Advanced Techniques