Python 3.10 added a new way to branch on a value: the match statement. It looks like the switch statement from other languages, but it does more — it can match patterns, not just exact values.

The simple form

status: str = "approved"

match status:
    case "approved":
        print("Welcome aboard.")
    case "pending":
        print("Please wait.")
    case "rejected":
        print("Sorry, try again next time.")
    case _:
        print("Unknown status.")
  • match status: says “look at the value of status”.
  • Each case checks one option.
  • case _: is the catch-all — _ matches anything, like an else.

This is equivalent to a chain of if/elif/else, just easier to read when you’re branching on the same value.

Matching multiple values in one case

Use the | operator to match any of several values:

match status:
    case "approved" | "verified":
        print("Welcome.")
    case "pending" | "in_review":
        print("Hold on.")
    case _:
        print("Other.")

Matching with conditions (guards)

You can add an if to a case — called a guard. The case only matches if both the pattern fits and the guard is true:

age: int = 17

match age:
    case n if n < 13:
        print("Child")
    case n if n < 18:
        print("Teenager")
    case n if n < 65:
        print("Adult")
    case _:
        print("Senior")

The variable n captures the value of age so the guard can reference it.

Matching shapes — the real power

match can pull apart lists, tuples, and dictionaries. This is where it goes beyond a simple switch.

Matching a tuple

def describe_point(point: tuple[int, int]) -> str:
    match point:
        case (0, 0):
            return "Origin"
        case (0, _):
            return "On the Y-axis"
        case (_, 0):
            return "On the X-axis"
        case (x, y):
            return f"At ({x}, {y})"


print(describe_point((0, 0)))    # Origin
print(describe_point((0, 5)))    # On the Y-axis
print(describe_point((3, 4)))    # At (3, 4)
  • (0, 0) matches the exact tuple (0, 0).
  • (0, _) matches any tuple starting with 0.
  • (x, y) matches any 2-tuple, and binds x and y to its values.

We won’t go through every advanced pattern (lists, dicts, classes) here — match is rarely used at the beginner level. But you’ll see it in modern Python code and it’s worth recognising.

Matching a dictionary

event: dict[str, str | int] = {"type": "click", "x": 10, "y": 20}

match event:
    case {"type": "click", "x": x, "y": y}:
        print(f"Click at ({x}, {y})")
    case {"type": "keypress", "key": key}:
        print(f"Key pressed: {key}")
    case _:
        print("Unknown event")

The pattern {"type": "click", "x": x, "y": y} matches dictionaries with a type key equal to "click", and binds the x and y keys’ values.

When to use match vs if/elif/else

  • One or two branches — use if/else.
  • Several branches checking the same variable for exact valuesmatch reads better than a long elif chain.
  • Branching on the shape of data (tuples, dicts) — match is the right tool.

You won’t reach for match every day. But when you need it, it’s much cleaner than the alternatives.

Summary of Section 4

You now know how to:

  • Make decisions with if/elif/else
  • Loop through collections with for
  • Loop while a condition holds with while
  • Skip or exit loops with continue and break
  • Generate numbers with range()
  • Branch on patterns with match/case

With control flow, variables, types, and operators, you can write small but real programs. Next up is the biggest building block of all — functions.

What’s next

Section 5: Functions — defining your own reusable blocks of code, with type hints.

Toggle theme (T)