Lesson 6: Loop Control, Nested Loops & The else Clause
Master break, continue, pass, loop else clauses, and nested loops with trace tables.
Taking Full Control of Loops
Plain for and while loops get you 80% of the way. The remaining 20% — fine-grained control — is what separates beginner code from professional code. This lesson covers the three interrupts, the secret else clause, and nested loops.
What You'll Learn in This Lesson
- Use
break,continue, andpassprecisely - Master the loop
elseclause — Python's hidden gem - Build nested loops for grids, tables, and combinations
- Use
enumerate()andzip()to iterate like a pro
The Three Interrupts
| Keyword | Behavior | Perfect for |
|---|---|---|
break |
Stop the loop NOW | Searching: "found it, stop looking" |
continue |
Skip this item, next iteration | Filtering inside loops |
pass |
Do nothing | Placeholder where syntax needs a body |
pass is subtle: it is not a loop keyword, but a statement that does nothing. Use it when the grammar requires a block but you are not ready to write it:
for item in items:
pass # TODO: implement later — prevents an IndentationError
When to use
pass: any place Python requires an indented block but you have nothing to write yet — empty function bodies, empty class bodies, empty exception handlers. It is the "I'll finish this later" placeholder.
The Secret else Clause
A loop's else block runs only if the loop finished without hitting break. This is a clean, Pythonic way to say "search failed":
numbers = [4, 8, 15, 16, 23, 42]
target = 16
for n in numbers:
if n == target:
print(f"Found {target} at position {numbers.index(n)}")
break
else:
print(f"{target} not found")
- Found it →
breakruns →elseis skipped. - Not found → loop ends naturally →
elseruns.
Without
else, you would need a boolean flag (found = False...) — the loopelseremoves that boilerplate. It is one of the most "Pythonic" features in the language.
The Flag-Variable Alternative (and Why else Is Better)
The non-else way to write the same logic:
found = False
for n in numbers:
if n == target:
print("Found it!")
found = True
break
if not found:
print("Not found")
The loop else version is shorter, has no flag to forget, and keeps the "not found" handling right next to the search. This pattern appears in real code constantly — prime-number checks, password validators, and duplicate detectors.
Nested Loops — Loops Inside Loops
A loop inside a loop runs the inner loop completely for every single outer iteration:
for i in range(1, 4): # outer: 3 times
for j in range(1, 4): # inner: runs fully 3 times
print(f"{i}x{j}={i*j}", end=" ")
print() # newline after each row
1x1=1 1x2=2 1x3=3
2x1=2 2x2=4 2x3=6
3x1=3 3x2=6 3x3=9
- The outer counter moves slowly — like the hour hand.
- The inner counter resets every row — like the minute hand doing a full sweep per hour.
- Use nested loops for grids, multiplication tables, and combinations.
Trace with two counters: build a table with columns
iandj. For every value ofi, list all values ofj. You will literally see the pattern.
Iteration Counts
With m outer iterations and n inner iterations, the inner body runs m × n times total. For the 3×3 table above, that is 9 printed cells — and a for i in range(10): for j in range(10): grid prints 100 cells. This multiply-out is how you estimate whether nested loops will be fast enough for large data (a 10,000 × 10,000 nested loop is 100 million steps — slow!).
enumerate() and zip() — Pro Iteration Tools
enumerate() gives you both the index and the value:
names = ["Amol", "Riya", "Sam"]
for i, name in enumerate(names, start=1):
print(f"{i}. {name}")
# 1. Amol
# 2. Riya
# 3. Sam
zip() pairs two sequences side by side:
names = ["Amol", "Riya"]
scores = [95, 88]
for name, score in zip(names, scores):
print(name, score)
# Amol 95
# Riya 88
Mental model:
enumeratehands out numbered tickets as each person enters.zipis a zipper joining two rows of teeth into one.
zip with more than two lists works the same way, and it stops at the shortest input — perfect for combining parallel lists of scores, names, and grades.
Common Mistakes to Avoid
- Mistake: Using a flag variable when
elsewould work — Fix: prefer the loopelsefor "not found" logic. - Mistake: 3+ levels of nested loops — Fix: break them into functions; deep nesting is a readability killer.
- Mistake: Forgetting to update the counter in a
whileloop — Fix: always move toward the exit condition. - Mistake: Putting
elseat the wrong indentation — Fix: the loopelsemust be at the same indent as thefor/while, not inside the loop body. - Mistake: Using
passwhere you meantcontinue— Fix:passdoes nothing and falls through;continuejumps to the next iteration.
Professional Tips & Tricks
- Prefer
break + elseover a boolean flag likefound = False— it is more Pythonic. - Avoid deeply nested loops (3+ levels); break them into functions.
for i, v in enumerate(items)gives both index and value.- Use
zip(names, scores, grades)to walk parallel lists in lockstep. - Print loop counters while debugging — instant trace table.
Key Takeaways
breakexits,continueskips,passis a placeholder.- Loop
elseruns only when nobreakhappened — perfect for search-failed logic. - Nested loops = inner loop completes fully per outer iteration.
enumerate()andzip()remove index/bookkeeping boilerplate.- Inner body runs
m × ntimes in nested loops — always estimate the total.
Next up: Comprehensions — build lists, dicts, and sets in one elegant line.
# break / continue / else / nested loops
print("--- search with break + else ---")
numbers = [4, 8, 15, 16, 23, 42]
target = 16
for n in numbers:
if n == target:
print(f"Found {target} at position {numbers.index(n)}")
break
else:
print(f"{target} not found")
print("--- skip with continue ---")
for n in range(1, 11):
if n % 3 == 0:
continue
print(n, end=" ")
print()
print("--- multiplication table (nested loops) ---")
for i in range(1, 4):
for j in range(1, 4):
print(f"{i}x{j}={i*j}", end=" ")
print()Lesson Code (Python)
# break / continue / else / nested loops
print("--- search with break + else ---")
numbers = [4, 8, 15, 16, 23, 42]
target = 16
for n in numbers:
if n == target:
print(f"Found {target} at position {numbers.index(n)}")
break
else:
print(f"{target} not found")
print("--- skip with continue ---")
for n in range(1, 11):
if n % 3 == 0:
continue
print(n, end=" ")
print()
print("--- multiplication table (nested loops) ---")
for i in range(1, 4):
for j in range(1, 4):
print(f"{i}x{j}={i*j}", end=" ")
print()Console Output
--- search with break + else ---
Found 16 at position 3
--- skip with continue ---
1 2 4 5 7 8 10
--- multiplication table (nested loops) ---
1x1=1 1x2=2 1x3=3
2x1=2 2x2=4 2x3=6
3x1=3 3x2=6 3x3=9Code Visualization Tips
- Trace a nested loop like a table: outer counter moves slowly, inner counter resets every row.
- For break/else, ask: 'did the loop end because it found something, or because it ran out of items?'
- Print the loop counters inside the loop while debugging — instant trace table.
Professional Tips & Tricks
- Prefer break + else over a boolean flag like found = False — it is more Pythonic.
- Avoid deeply nested loops (3+ levels); break them into functions.
- for i in range(n) with enumerate() gives both index and value: for i, v in enumerate(items).
Python Code Judge & Practice Arena
LeetCode StyleRun real Python 3.12 WebAssembly code directly in your browser against automated test suites.
Problem 1: Diagonal Matrix Sum 1
Test Your Knowledge
Instant feedbackQuick Check: Lesson 6: Loop Control, Break, Continue, Pass & Nested Loops
Up next · Continue learning
Comprehensions — Clean, Fast Loops
Build lists, dicts, and sets in one elegant line with comprehensions and generator expressions.