match/case structural pattern matching (PEP 634)
Beyond simple value matching, case patterns can destructure sequences, mappings, and objects (via
__match_args__), combine alternatives with |, and attach a case ... if <guard>: condition. It's closer
to real pattern matching (Rust/Haskell-style) than a fancy switch -- it binds names as it matches.
def describe(x):
match x:
case 0:
return "zero"
case int() | float() if x < 0:
return "negative number"
case [a, b]:
return f"pair: {a}, {b}"
case [a, *rest]:
return f"list starting with {a}, {len(rest)} more"
case {"type": "point", "x": px, "y": py}:
return f"point dict at {px},{py}"
case str():
return "a string"
case _:
return "something else"
for val in [0, -5, [1, 2], [1, 2, 3, 4], {"type": "point", "x": 1, "y": 2}, "hi", 3.5]:
print(f"{val!r:34} -> {describe(val)}")
A class with __match_args__ can be destructured positionally, and guards can compare the bound fields to each other:
class Point:
__match_args__ = ("x", "y")
def __init__(self, x, y):
self.x, self.y = x, y
def classify(p):
match p:
case Point(0, 0):
return "origin"
case Point(x, 0):
return f"on x-axis at {x}"
case Point(x, y) if x == y:
return "on the diagonal"
case Point():
return "somewhere else"
for p in [Point(0, 0), Point(5, 0), Point(3, 3), Point(1, 2)]:
print(f"({p.x},{p.y}) -> {classify(p)}")