Python Match Case
match compares one value against a list of patterns and runs the block for the first pattern that fits. It is Python’s answer to the switch statement found in other languages, and it can also pull values out of lists and dictionaries.
- Replace long elif chains with match
- Combine values with OR patterns
- Add conditions with guards
- Match and unpack lists and dicts
Your first match statement
match was added in Python 3.10. Each case is a pattern. _ is the wildcard: it matches anything, so it works like else.
status_code = 404 match status_code: case 200: print("OK") case 404: print("Not found") case 500: print("Server error") case _: print("Unknown status")Not found
Only the first matching case runs. Unlike C or Java, there is no fall-through and no break needed.
Several values in one case
Use | to mean “or”:
def day_type(day): match day.lower(): case "saturday" | "sunday": return "weekend" case "monday" | "tuesday" | "wednesday" | "thursday" | "friday": return "weekday" case _: return "not a day" for d in ["Sunday", "wednesday", "Funday"]: print(d, "->", day_type(d))Sunday -> weekend wednesday -> weekday Funday -> not a day
Capture a value and add a guard
A bare name in a pattern captures the value. An if after the pattern is a guard: the case matches only if the guard is true.
def grade(score): match score: case n if n >= 90: return "A" case n if n >= 75: return "B" case n if n >= 0: return "C or below" case _: return "invalid" print(grade(95), grade(80), grade(40), grade(-5))A B C or below invalid
For simple range checks like this, if / elif is just as clear. match really shines when you need to look at the shape of the data, as below.
Match sequences
Patterns can describe lists and tuples. Names in the pattern are filled from the matching positions, and *rest collects the remaining items.
def run(command): match command.split(): case ["quit"]: return "Bye" case ["go", direction]: return f"Going {direction}" case ["take", first, *others]: return f"Taking {first} and {len(others)} more" case []: return "Say something" case _: return f"Unknown command: {command!r}" for c in ["go north", "take key lamp rope", "quit", "", "dance"]: print(run(c))Going north Taking key and 2 more Bye Say something Unknown command: 'dance'
Match dictionaries
A mapping pattern checks that certain keys exist and captures their values. Extra keys are ignored, which makes this ideal for JSON from an API.
events = [ {"type": "click", "x": 10, "y": 20}, {"type": "key", "key": "Enter"}, {"type": "scroll"},] for event in events: match event: case {"type": "click", "x": x, "y": y}: print(f"click at ({x}, {y})") case {"type": "key", "key": key}: print(f"key {key} pressed") case {"type": other}: print(f"unhandled event {other}")click at (10, 20) key Enter pressed unhandled event scroll
Match by type
int(), str() and other class names in a pattern check the type:
def describe(value): match value: case bool(): return "a boolean" case int() | float(): return "a number" case str() if value == "": return "an empty string" case str(): return "a string" case list(): return f"a list of {len(value)}" case _: return "something else" for v in [True, 3, 2.5, "", "hi", [1, 2], None]: print(repr(v), "is", describe(v))True is a boolean 3 is a number 2.5 is a number '' is an empty string 'hi' is a string [1, 2] is a list of 2 None is something else
bool() is checked before int() because True is also an int. As with elif, put the more specific case first.
Check your understanding
Predict the output
point = (0, 5)match point: case (0, 0): print("origin") case (0, y): print(f"on the y axis at {y}") case (x, 0): print(f"on the x axis at {x}") case _: print("somewhere else")on the y axis at 5
The second pattern needs a first item of 0 and captures the second item as y, so it matches (0, 5).
Quick quiz
1. Which Python version introduced match?
Structural pattern matching arrived in Python 3.10.
2. What does case _: do?
_ is the wildcard pattern.
3. How do you match “y” or “yes” in one case?
| combines alternatives in a pattern.
Exercise: calculator
Write calc(a, op, b) with match that supports +, -, * and /, returns “cannot divide by zero” for division by 0, and “unknown operator” otherwise.
calc(6, "*", 7), calc(9, "/", 0), calc(9, "/", 3), calc(1, "^", 2)
42 cannot divide by zero 3.0 unknown operator
Hint 1
A guard like case "/" if b == 0: must come before case "/":.
def calc(a, op, b): match op: case "+": return a + b case "-": return a - b case "*": return a * b case "/" if b == 0: return "cannot divide by zero" case "/": return a / b case _: return "unknown operator" print(calc(6, "*", 7), calc(9, "/", 0), calc(9, "/", 3), calc(1, "^", 2))42 cannot divide by zero 3.0 unknown operator
The guarded division case is checked before the plain one, so dividing by zero never reaches a / b.
Program Practice
The if-else programs are a great place to practise match: try rewriting a few solutions with it.
64 Python If-Else Programs
Every program has a step-by-step explanation, colour-coded code and its real output.
Python match case FAQ
Does Python have a switch case statement?
Yes, since Python 3.10 the match statement does everything a switch does, plus matching on the structure of lists, tuples, dicts and objects.
Do I need break in Python match case?
No. Only the first matching case runs and there is no fall-through.
What is the default case in Python match?
case _: matches any value, so it acts as the default.
Is match faster than if elif?
Not meaningfully. Choose match when it makes the code clearer, especially when unpacking structured data.