Match Statement
status = 500
match status:
case 404:
print("Not found")
case 418:
print("I'm a teapot")
# Wildcard case
case _:
print("Some other status")
Creating a case such as case var: is not allowed,
even when var is defined above.
Python binds the matched value to var and it would always match.
Match statements do not fall through.
Or Patterns
match 1:
case 2 | 3:
print("2 or 3")
match [1, 2]:
case [1, 2 | 3]:
print("1, 2 or 3")
This is allowed with all types as long as each case binds the same variables, for example
[1, x] | [x, 2]. Cases in the pattern are evaluated left-to-right.
Match Guards
msg = "OK"
status = 0
match msg:
case "OK" if status == 1:
print("Good response")
case _ if status == 0:
print("Bad time")
case _:
pass
# Output: Bad time
The if statement is only evaluated if the pattern matches initially and after all the pattern variables have been bound.
Using The Matched Value
match ("go", "south"):
case ("go", "north" | "south" as direction):
print(f"You head {direction}")
The as keyword can be used to bind any otherwise unnamed value in the case.
Lists & Tuples
m = 4
match [3, 4, 5]:
# `x` and `y` are bound here
case [x, y]:
print(f"Any two-element list {x}, {y}")
# `m` is from the outer scope
case [m, 4]:
print(f"Two-element list 4, 4")
case [3, *rest]:
print("3", rest)
case _: # Equivalent to [*items]
pass
# Output: 3, [4, 5]
This always matches the exact number of list elements. This is the same for Tuples.
Dictionaries
match {"name": "Bob", "age": 32}:
# `n` is bound here
case {"name": "James", "age": n}:
print(n)
case {"name": "Bob"}:
print("It's Bob.")
Unlike the list example, dictionary cases match when the set of keys in the value is a superset of the case.
For example, the second case in the above example will match even though
the value has an extra key: "age".
Objects
class Ok:
__match_args__ = ("value",)
def __init__(self, value):
self.value = value
class Err:
def __init__(self, err_msg):
self.err_msg = err_msg
match Ok(5):
case Ok(n):
print(f"Value: {n}")
case Err(err_msg=msg): # Without __match_args__
print(f"Error: {msg}")
Builtin Types
var = 1
match var:
case str():
print("String")
case bool():
print("Boolean")
case int():
print("Integer")
bool() must come before int() to distinguish them.
Boolean values are coerced to integers, so otherwise the integer case would match before the boolean case.
The cases do not create instances of the types.
from typing import Type
import builtins # Cannot use `from builtins import str`
type_var: Type = str
match type_var:
case builtins.str:
print("String")
case builtins.int:
print("Integer")