Python Control Flow
- Description:
if/elif/else, conditional expressions,for/whileloops, theelseclause on loops,match/casepattern matching, and the walrus operator:= - My Notion Note ID: K2A-D1-7
- Created: 2022-07-02
- Updated: 2026-05-11
- License: Reuse is very welcome. Please credit Yu Zhang and link back to the original on yuzhang.io
Table of Contents
- 1.
if/elif/else - 2. Loops
- 3.
match/case(Structural Pattern Matching) - 4. The Walrus Operator
:=
1. if / elif / else
if x > 0:
sign = 1
elif x < 0:
sign = -1
else:
sign = 0
- No C-style
switchbefore 3.10,elifchains take its place - Since 3.10,
match/caseprovides a more powerful alternative
1.1 Conditional Expression
status = "even" if n % 2 == 0 else "odd"
y = a / b if b != 0 else 0
- Order is
value_if_true if cond else value_if_false, condition in the middle (unlike C++cond ? a : b) - Use only for short, side-effect-free expressions
2. Loops
2.1 for-in
- Always over an iterable, no C-style
for (int i = 0; ...) - To get indices: use
rangeorenumerate
for x in xs: # value iteration
...
for i in range(len(xs)): # index iteration (rarely the right answer)
...
for i, x in enumerate(xs): # both, preferred
...
for a, b in zip(xs, ys):
...
- Modifying a list while iterating over it is undefined, iterate over a copy (
xs[:]) or build a new list
2.2 while
while not done:
done = step()
while True:withbreakis common and idiomatic- No
do { ... } while ();
2.3 break, continue, pass
break, exit innermost loopcontinue, next iterationpass, do nothing; placeholder where a statement is required
if x < 0:
pass # TODO: handle later
else:
process(x)
class TODO:
pass # empty class body
- No labeled
break, refactor into a function andreturn, or use a flag
2.4 else on a Loop
for/whilemay have anelseblock that runs if the loop completed WITHOUT hittingbreak- Read as
nobreak
for n in candidates:
if is_prime(n):
first_prime = n
break
else:
raise ValueError("no prime in candidates")
- Wrap in a function and
returnif the construct hurts readability
3. match / case (Structural Pattern Matching)
PEP 634 (3.10+). Destructures tuples, lists, dicts, and classes:
def handle(event):
match event:
case ("click", x, y):
click(x, y)
case ("key", key) if key in modifiers:
modifier_press(key)
case {"type": "scroll", "dy": dy}:
scroll(dy)
case Point(x=0, y=0):
origin()
case [head, *tail]:
recur(head, tail)
case _:
unknown(event)
- Patterns matched top-to-bottom
_= wildcardcase Cls(field=...)matches an instance and binds fields (needs__match_args__or named fields;@dataclassprovides automatically)case ... if cond:adds a guard- Captures use bare names:
case x:BINDSx. To match a constant, use a dotted name (case Color.RED:) or quote (case "red":)
4. The Walrus Operator :=
PEP 572 (3.8+), "assignment expression". Assign and use a value in one expression.
while (line := f.readline()):
process(line)
if (n := len(buffer)) > MAX:
raise ValueError(f"buffer too large: {n}")
[y for x in data if (y := transform(x)) is not None]
- Use sparingly, only for genuine readability gains
- Not allowed at the top level of an expression statement (
x := 1alone is a syntax error)