When one loop isn't enough
The problem...
You need to loop through something. And for every item — loop through something else.
A table. A grid. Every combination of two sequences. One loop can't do it alone.
The idea!
You can put a for loop inside another for loop. The outer loop runs once per item. For every outer iteration — the inner loop runs completely.
The syntax
for outer_item in outer_sequence:
for inner_item in inner_sequence:
# runs for every combination
Two levels of indentation. The inner block is indented 8 spaces from the left — 4 for the outer loop, 4 more for the inner.
Your first nested loop
for i in range(1, 4):
for j in range(1, 4):
print(f"{i} x {j} = {i * j}")
# 1 x 1 = 1
# 1 x 2 = 2
# 1 x 3 = 3
# 2 x 1 = 2
# 2 x 2 = 4
# 2 x 3 = 6
# 3 x 1 = 3
# 3 x 2 = 6
# 3 x 3 = 9
The outer loop runs 3 times. Each time — the inner loop runs 3 times. 3 × 3 = 9 lines total.
What's really happening
# i = 1 → inner loop runs: j = 1, 2, 3
# i = 2 → inner loop runs: j = 1, 2, 3
# i = 3 → inner loop runs: j = 1, 2, 3
The inner loop completes fully before the outer loop moves to the next item.
Looping through two strings
vowels = "aeiou"
word = "Bull"
for letter in word:
for vowel in vowels:
if letter == vowel:
print(f"{letter} is a vowel")
# u is a vowel
For every letter in word — check it against every vowel. If it matches — print it.
Heads up!
- The inner loop runs completely for every outer iteration
- Total iterations = outer count × inner count
- Each level adds 4 spaces of indentation
- Nested loops get slow with large sequences — keep them small at this stage
The mindset shift
Stop thinking: "I need one loop per task."
Start thinking: "For every item in A — do something with every item in B."
What you should understand now
- A nested loop is a loop inside a loop
- The inner loop runs completely before the outer loop moves on
- Total iterations = outer × inner
- Each level of nesting adds 4 spaces of indentation