Control flow#
Control flow is how the operator’s program decides what runs
next. Python keeps the surface small: if / elif /
else for branching, for and while for iteration,
match / case for destructuring, and break /
continue / return / pass / raise for jumps.
This page is the day-to-day reference for the control-flow
constructs in the language. For the values they branch on, see
Types. For functions and the patterns they enable (early
return, recursion, generators), see Functions. For the
exception flow raise participates in, see Errors.
Conditional#
if / elif / else evaluates branches top-to-bottom and
takes the first that matches. elif is sugar for else: if.
flowchart TD
A([start]) --> B{x > 0?}
B -->|true| C[positive]
B -->|false| D{x == 0?}
D -->|true| E[zero]
D -->|false| F[negative]
C --> Z([end])
E --> Z
F --> Z
if x > 0:
positive()
elif x == 0:
zero()
else:
negative()
Conditional expressions (the ternary form) inline a branch as an expression.
z = a if cond else b
Useful inside list-comprehensions or assignments where a full
if statement would be heavy.
label = "even" if n % 2 == 0 else "odd"
Truthiness rules (False, None, 0, 0.0, empty
containers, anything whose __bool__ returns False)
determine what counts as true in a condition. See
Types for the full table.
Idioms#
Empty check; reach for the truthy form, not == [] or
len(xs) == 0.
if not items:
return
Membership against a small fixed set, cleaner than a chain of
== comparisons.
if x in {1, 2, 3}:
handle(x)
Type test with isinstance; accepts a tuple of types.
if isinstance(x, (int, float)):
handle_number(x)
Bind-and-test with the walrus := to avoid recomputing or
re-fetching the value.
if (n := len(payload)) > MAX_SIZE:
raise ValueError(f"payload too large: {n} bytes")
Loops#
for iterates anything implementing __iter__; while
loops while the condition is truthy. Both accept an optional
else clause that runs only if the loop exits without
break.
For loop#
flowchart TD
A([start]) --> B{more in iterable?}
B -->|yes| C[bind item]
C --> D[body]
D --> B
B -->|no| E([end])
Iterate anything implementing __iter__; the standard form
the operator reaches for first.
for item in iterable:
handle(item)
Index and value at once with enumerate.
for i, item in enumerate(xs, start=1):
print(i, item)
Parallel iteration with zip; stops at the shortest.
for a, b in zip(xs, ys):
combine(a, b)
Walk a mapping’s key-value pairs.
for k, v in mapping.items():
store(k, v)
Walk a sequence in reverse without materialising a copy.
for x in reversed(xs):
handle(x)
File iteration is line-by-line; the file object itself is the iterable.
for line in open("log.txt"):
parse(line)
Cross-products, permutations, and adjacent pairs come from
itertools.
from itertools import product, permutations, combinations, pairwise
for a, b in pairwise(xs):
diff(a, b)
Iterate keys in a fixed order without sorting in place.
for k in sorted(d):
handle(k, d[k])
Idiomatic loop forms at a glance.
Form |
When |
|---|---|
|
Direct iteration; never |
|
Index and value at once. |
|
Parallel iteration; stops at the shortest. |
|
Walk a mapping’s key-value pairs. |
|
Walk keys in sorted order. |
|
Cross-products and orderings. |
|
Adjacent pairs (3.10+). |
While loop#
flowchart TD
A([start]) --> B{cond truthy?}
B -->|yes| C[body]
C --> B
B -->|no| D[else clause]
D --> E([end])
Standard form with an optional else clause that runs only
when the loop exits without break.
while cond:
step()
else:
cleanup()
Walrus := in the condition binds and tests in one go;
avoids the read-then-check duplication.
while (chunk := f.read(4096)):
process(chunk)
Loop-else#
The else clause on a loop runs only if the loop exits
without break. Useful for search-then-fallback patterns.
for x in xs:
if found(x):
break # else clause is skipped
else:
not_found() # runs only if no break fired
Match-case#
match / case (Python 3.10+) destructures values against
patterns. Each case is tried top-to-bottom; the first match
wins. _ is the wildcard.
flowchart TD
A([match subject]) --> B{case 1 matches?}
B -->|yes| C[case 1 body]
B -->|no| D{case 2 matches?}
D -->|yes| E[case 2 body]
D -->|no| F{...}
F --> G[case _ body]
C --> Z([end])
E --> Z
G --> Z
match command.split():
case ["go", direction]:
move(direction)
case ["set", *args] if args:
configure(args)
case {"type": "click", "pos": (x, y)}:
click(x, y)
case Point(x=0, y=0):
at_origin()
case _:
unknown()
Pattern kinds you should know.
Pattern |
Matches |
|---|---|
|
exact value: |
|
any value; binds the name (note: |
|
any value; binds nothing (wildcard) |
|
sequence with at least two elements; binds |
|
mapping with |
|
instance with matching attributes |
|
either pattern matches (alternation) |
|
pattern with a boolean guard |
Jumps#
The five primitives that interrupt the natural top-to-bottom flow of a block.
Keyword |
Effect |
|---|---|
|
Exit the innermost |
|
Skip the rest of the loop body, jump to the next iteration. |
|
Exit the current function with a value (default
|
|
No-op. Use as a placeholder when a block is required but the operator has nothing to put in it yet. |
|
Throw an exception (see Errors). |
Early return on success, explicit fall-through return for
the no-match case.
def first_match(items, pred):
for x in items:
if pred(x):
return x
return None
continue and break together model a scan-with-skip
loop.
for line in lines:
if line.startswith("#"):
continue
if line.strip() == "STOP":
break
process(line)
return from a generator (def with yield) raises
StopIteration with the return value as its argument. pass
in an if body or class body is the operator’s “TODO” marker
that still parses.
References#
Syntax for the lexical surface
if/for/while/matchlive in.Types for truthiness rules and what counts as “true” in a condition.
Functions for
return, generators, and comprehensions as expression-form loops.Errors for
raiseand the exception-driven flow patterns.PEP 634, structural pattern matching.