Skip to content

Pattern Matching in Python

PEP-0636

Matching a python builtin type

def fib(n: int):
    match n:
        case 0:
            return 0
        case 1:
            return 1
        case n:
            return fib(n - 1) + fib(n - 2)

fib(10)
55

Matching a python list

def sum_list(xs: list[int]) -> int:
    match xs:
        case [x]:
            return x
        case [x, *ys]:
            return x + sum_list(ys)

assert(
    sum_list(list(range(10))) == sum(range(10))
)

Matching Python enums

from datetime import date
import enum
class Weekday(enum.Enum):
    MONDAY = 1
    TUESDAY = 2
    WEDNESDAY = 3
    THURSDAY = 4
    FRIDAY = 5
    SATURDAY = 6
    SUNDAY = 7



def is_day_a_weekend(day: Weekday):
    match day:
        case Weekday.SATURDAY | Weekday.SUNDAY:
            print(f"Yippee it's {day.name}!")
        case _:
            print(f"We are {6 - day.value} day(s) away from Saturday")

is_day_a_weekend(Weekday.FRIDAY)
is_day_a_weekend(Weekday.SATURDAY)
We are 1 day(s) away from Saturday
Yippee it's SATURDAY!

Matching with multiple predicates and wildcards

Fizz-Buzz program

def fizz_buzz(n: int) -> str:
    """
    num == "FizzBuzz" if num is divisible by 3 and 5.
    num == "Fizz" if num is divisible by 3.
    num == "Buzz" if num is divisible by 5.
    num == num (as a string) if none of the above conditions are true.

    Args:
        n (int): A positive integer.

    Returns:
        str: FizzBUzz string for the num.
    """
    match (n % 3, n % 5):
        case (0, 0):
            return "FizzBuzz"
        case (0, _):
            return "Fizz"
        case (_, 0):
            return "Buzz"
        case _:
            return str(n)

for num in range(10, 16):
    print(f"{num=} {fizz_buzz(num)}")
num=10 Buzz
num=11 11
num=12 Fizz
num=13 13
num=14 14
num=15 FizzBuzz
from collections import namedtuple
Point = namedtuple("Point", "x y")
point = Point(2, 4)

match point:
    case Point(x=a, y=b):
        print(a, b)
    case _:
        print("nope!")
2 4
data = {"b": 20, "a": 10}
match data:
    case {"a": a, **others}:
        print(a)
    case {"b": b, **others}:
        print(b)
    case _:
        print(data)
10
import requests

response = requests.get("https://pavithranrao.github.io")
match response.status_code:
    case 200:
        print(len(response.content))
    case x if x >= 400:
        print(f"HTTPError: {response.reason}")
    case _:
        print(response)
18586

Matching a Python class or dataclass

import dataclasses

@dataclasses.dataclass
class Command:
    command_type: str
    command_args: list[str]

def perform_fn(command: Command):
    match command:
        case Command(command_type, command_args) if command_type == "echo":
            print(command_args[0])
        case _:
            print("unimplemented command!")

echo = Command(
    command_type="echo",
    command_args=["Hello, World!"]
)
perform_fn(echo)
Hello, World!

Foot Note

I also found these blogs useful: