Control flowChapter 44 of 114
Match
Structural pattern matching, and where it beats a chain of elif.
The basic form
match compares a value against a series of patterns and runs the first one that fits:
command = "start"
match command:
case "start":
print("Starting")
case "stop":
print("Stopping")
case _:
print("Unknown command")Output
Starting
case _ is the catch-all, equivalent to else. Without it, an unmatched value simply falls through and nothing happens.
Several values in one case
for key in ["q", "x", "a"]:
match key:
case "q" | "x":
print(key, "-> quit")
case _:
print(key, "-> ignored")Output
q -> quit x -> quit a -> ignored
The | means "or". There is no fall-through between cases, so no break is needed.
Matching structure, not just values
This is what match is actually for, and where a chain of elif gets ugly. Patterns can destructure the value:
points = [(0, 0), (5, 0), (0, 3), (2, 4)]
for point in points:
match point:
case (0, 0):
print("origin")
case (x, 0):
print(f"on the x axis at {x}")
case (0, y):
print(f"on the y axis at {y}")
case (x, y):
print(f"somewhere at {x},{y}")Output
origin on the x axis at 5 on the y axis at 3 somewhere at 2,4
Names in a pattern are bound, not compared. case (x, 0) matches any pair whose second item is zero, and x becomes the first item.
Matching dictionaries
Handling JSON-shaped data is where this earns its place:
events = [
{"type": "click", "x": 10, "y": 20},
{"type": "key", "value": "a"},
{"type": "scroll"},
]
for event in events:
match event:
case {"type": "click", "x": x, "y": y}:
print(f"click at {x},{y}")
case {"type": "key", "value": value}:
print(f"key {value}")
case {"type": kind}:
print(f"unhandled: {kind}")Output
click at 10,20 key a unhandled: scroll
A dictionary pattern matches on the keys it names and ignores any others, which is what makes it robust against extra fields.
Guards
An if on a case adds a condition the pattern alone cannot express:
for value in [5, 50, -3]:
match value:
case n if n < 0:
print(n, "negative")
case n if n > 10:
print(n, "large")
case n:
print(n, "small")Output
5 small 50 large -3 negative
Matching classes
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
match Point(0, 7):
case Point(x=0, y=y):
print("on the y axis at", y)
case Point():
print("somewhere else")Output
on the y axis at 7
When to use it
match needs Python 3.10 or newer. Reach for it when you are picking apart the shape of data — tuples, dictionaries, objects. For a simple value check, an if/elif chain is shorter and every reader already knows it.
Test yourself
2 questionsIn 'case (x, 0):', what does x do?
Show the answer
Binds to the first item of any pair whose second item is 0 — Bare names in a pattern bind rather than compare, which is why 'case limit:' matches everything.
What does a dictionary pattern do about keys it does not name?
Show the answer
Ignores them — That is what makes match robust against extra fields in JSON-shaped data.
While Loops
Repeat while a condition holds, and make sure it eventually stops.