CurriculumPython for Loops and range() for KidsLoops inside loops
Nested for Loops in Python: A Loop Inside a Loop
A loop inside a loop, for checking every cell of a grid — and the order that surprises everyone.
Loops inside loops
So far every loop you've written stands alone. Now let's put one loop INSIDE another.
This checks every cell of a 2x2 grid — row by row, and within each row, column by column.
for row in range(2):
for col in range(2):
print(row, col)Output
0 0
0 1
1 0
1 1Look at that order closely. row stays 0 for TWO full lines — col runs 0, then 1 — before row ever becomes 1.
for row in range(2):
for col in range(2):
print(row, col)That's the whole trick: the INNER loop (col) runs all the way to the end, every single time, before the OUTER loop (row) moves on even once. They never alternate.
This works the same way to read real grid contents — grid[row][col] picks row first, then the item at that column inside it.
grid = [["A", "B"], ["C", "D"]]
for row in range(2):
for col in range(2):
print(grid[row][col])Output
A
B
C
DCareful with which variable goes where. grid[row][row] would use row twice by accident — col has to be the one that changes the fastest, inside the brackets on the right.
grid = [["A", "B"], ["C", "D"]]
for row in range(2):
for col in range(2):
print(grid[row][col])One more thing worth counting: how many times does that innermost print() actually run?
for row in range(3):
for col in range(2):
print(row, col)Output
0 0
0 1
1 0
1 1
2 0
2 13 outer passes, 2 inner passes each — that's 3 times 2, not 3 plus 2. Six lines. Nested loops multiply, they don't just add.
Check your understanding
for row in range(2): for col in range(2): print(row, col) — what's the FIRST value row becomes AFTER col has printed both 0 and 1?
for row in range(2):
for col in range(2):
print(row, col)Why: The inner loop finishes ENTIRELY — every value col can take — before the outer loop moves to its next value. That's why the output is 0 0, 0 1, then 1 0, 1 1: two full inner passes under row=0, then two more under row=1. Nothing alternates.
grid = [["A", "B"], ["C", "D"]]. Inside the nested loop, a line reads print(grid[row][row]). What actually prints?
grid = [["A", "B"], ["C", "D"]]
for row in range(2):
for col in range(2):
print(grid[row][row])Why: grid[row][row] locks the second position to whatever row is, so col changing does nothing to this line's result. row=0: grid[0][0] twice -> A, A. row=1: grid[1][1] twice -> D, D. The fix is grid[row][col], so the SECOND position actually follows the inner loop.
An outer loop runs 4 times. Its inner loop runs 3 times on EACH of those passes. How many times does the innermost print() run in total?
Why: Every one of the outer loop's 4 passes triggers a COMPLETE run of the inner loop's 3 passes — 4 groups of 3, which is 12, not 4+3. This is why nested loops can produce output much longer than either number alone would suggest.
What you'll practice
This code visits every cell of a 2x2 grid using a loop inside a loop. Before you change anything, just RUN it and watch the order the coordinates come out in.
More from this topic
Loops inside loops is one lesson inside Python for Loops and range() for Kids — see the full lesson order and what the whole topic covers.
View the full topic →