Makes parsers, command dispatch and handling of nested JSON-like data far clearer than if-chains.
The match statement (3.10+) compares a value against patterns that describe its shape, binding names to the parts it extracts. The first matching case runs; nothing else does.
Pattern kinds:
- literal:
case 404:orcase "quit": - capture:
case x:matches anything and binds it tox;case _:is the wildcard that binds nothing - sequence:
case [x, y]:orcase [first, *rest]:match lists and tuples (but not strings) - mapping:
case {"type": "click", "pos": (x, y)}:matches dicts containing those keys; extra keys are allowed - class:
case Point(x=0, y=y):checksisinstanceand then attributes; positional forms likePoint(0, y)use the class's__match_args__, which dataclasses generate - or-patterns
case "y" | "yes":, as to bind a sub-pattern:case [int() as n, *_]: - guards:
case [x, y] if x == y:add an arbitrary condition
The big gotcha: a bare name is always a capture pattern, never a comparison against a variable. case RED: matches everything and rebinds RED. To compare against a constant, use a dotted name such as Color.RED (an enum member) or a literal.
Pattern matching shines for heterogeneous, nested data: parsed commands, AST nodes, JSON messages, event types. For a simple value switch, a dict lookup or if/elif is often just as clear. Note match isn't an expression; it doesn't return a value.
Example
from dataclasses import dataclass
from enum import Enum
class Color(Enum):
RED = "red"
@dataclass
class Point:
x: int
y: int
def describe(event):
match event:
case {"type": "click", "pos": Point(x, y)} if x == y:
return f"diagonal click at {x}"
case {"type": "key", "key": "q" | "Q"}:
return "quit"
case {"type": "paint", "color": Color.RED}:
return "painting red"
case _:
return "unknown"
print(describe({"type": "click", "pos": Point(3, 3)})) # diagonal click at 3
print(describe({"type": "key", "key": "Q", "time": 1})) # quit (extra keys ok)
print(describe({"type": "paint", "color": Color.RED})) # painting red
print(describe(["a", "b"])) # unknownRemember
- Patterns match by shape and bind names to the parts
- Bare names capture; compare to constants with dotted names or literals
- Mapping patterns ignore extra keys; class patterns use
__match_args__
Watch out for
- Writing
case SOME_CONSTANT:expecting a comparison — it captures and always matches.