for and while — Loops, the else Clause, and break/continue
~20 min · for, while, loop, else-on-loop
Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
for-each, not for-i
Python's for is a foreach over an iterable, not a C-style index counter. for x in seq: binds x to each element. There's no "for i in 0 to n." If you want indices, you use range(n). If you want both index and value, you use enumerate(seq). Internalizing this lets you stop translating mentally from C-style for-loops.
enumerate, zip, reversed — the loop trio
enumerate(seq) yields (index, value) pairs. zip(a, b, ...) yields tuples pairing items from each iterable, stopping at the shortest. reversed(seq) yields items in reverse order. Combine: for i, (a, b) in enumerate(zip(list1, list2)):. These three replace the entire genre of manual index management.
while — the workhorse for "until something"
Use while when the number of iterations isn't known up front: until input matches, until a condition is met, until a queue empties. The walrus operator := (3.8+) is great here for read-and-test patterns: while (line := f.readline()):. Don't reach for while True: with a manual break when a condition could go in the while directly.
break, continue, and the unloved else
break exits the innermost loop. continue skips to the next iteration. The strange one: else on a loop. The else block runs when the loop completes without breaking. It's perfect for "searching for something, do X if not found." It reads weird at first; once you know it, it can replace a flag variable cleanly.
Warning: Modifying a list while iterating it is a bug magnet. The safe move is iterate a copy (for x in items[:]) or build a new list with a comprehension and replace at the end.
Pythonic Way: If you find yourself writing for i in range(len(seq)), stop and use enumerate(seq). The only time range(len()) is right is when you genuinely don't need the value — and even then, ask yourself why.
Code
for-each over iterables·python
fruits = ["apple", "banana", "cherry"]
# Iterate values
for f in fruits:
print(f)
# With index — DON'T use range(len())
for i, f in enumerate(fruits):
print(i, f)
# Custom start index
for i, f in enumerate(fruits, start=1):
print(i, f)
# 1 apple
# 2 banana
# 3 cherry
zip — pair, triple, quadruple·python
names = ["alice", "bob", "charlie"]
ages = [30, 25, 35]
for name, age in zip(names, ages):
print(f"{name} is {age}")
# zip stops at the shortest
tickers = ["AAPL", "MSFT", "GOOG", "NVDA"]
prices = [180, 420, 145]
for t, p in zip(tickers, prices):
print(t, p)
# only 3 pairs printed — NVDA dropped
# zip(strict=True) raises if lengths differ — 3.10+
try:
for t, p in zip(tickers, prices, strict=True):
pass
except ValueError as e:
print(e)
while + walrus — read-and-test·python
import io
# Pretend this is a file
f = io.StringIO("line1\nline2\nline3\n")
# Old, awkward style
# while True:
# line = f.readline()
# if not line:
# break
# process(line)
# 3.8+ walrus — clean
while (line := f.readline()):
print("got:", line.strip())
# got: line1
# got: line2
# got: line3
else on a loop — runs if no break·python
def find_negative(items):
for i, x in enumerate(items):
if x < 0:
print(f"first negative at index {i}")
break
else:
print("no negative numbers")
find_negative([1, 2, 3]) # no negative numbers
find_negative([1, -2, 3]) # first negative at index 1
# else also works on while
n = 100
while n > 1:
if n % 2 == 1: # odd
print("hit an odd number")
break
n //= 2
else:
print("halved all the way down without odd")
# halved all the way down without odd
Modify-while-iterating bug, and the safe alternative·python
items = [1, 2, 3, 4, 5, 6]
# UNSAFE — strange behavior, can skip elements
# for x in items:
# if x % 2 == 0:
# items.remove(x)
# SAFE 1 — iterate a slice copy
items = [1, 2, 3, 4, 5, 6]
for x in items[:]:
if x % 2 == 0:
items.remove(x)
print(items) # [1, 3, 5]
# SAFE 2 — comprehension to a new list
items = [1, 2, 3, 4, 5, 6]
items = [x for x in items if x % 2 != 0]
print(items) # [1, 3, 5]
Given two parallel lists tickers = ["AAPL", "MSFT", "GOOG", "NVDA"] and prices = [180, 420, 145, 950]: (a) print each ticker and price using enumerate and zip together. (b) Find the first ticker priced under 200 — print its name and break. If none found, print 'all expensive' using the loop's else clause. (c) Use a while with the walrus operator to print each character of the string "pippa", one at a time, using iter and next (it = iter("pippa"); while (ch := next(it, None)):).
Progress
Progress is local-only — sign in to sync across devices.