Python Basics — Match-Case (Structural Pattern Matching)

3 minute read

Match-Case (Structural Pattern Matching)

Python 3.10 introduced match-case — a powerful way to branch based on the structure and value of data. Think of it as a smarter version of switch-case from other languages.

Requires Python 3.10+. Check your version: python --version

Basic Syntax

command = "quit"

match command:
    case "start":
        print("Starting...")
    case "stop":
        print("Stopping...")
    case "quit":
        print("Goodbye!")
    case _:
        print(f"Unknown command: {command}")

Output:

Goodbye!

The _ (underscore) is the wildcard pattern — it matches anything, like else in an if chain.

Matching Literals

def http_status(code):
    match code:
        case 200:
            return "OK"
        case 301:
            return "Moved Permanently"
        case 404:
            return "Not Found"
        case 500:
            return "Internal Server Error"
        case _:
            return f"Unknown status: {code}"

print(http_status(200))   # OK
print(http_status(404))   # Not Found
print(http_status(999))   # Unknown status: 999

Matching Multiple Values with |

day = "Saturday"

match day:
    case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
        print("Weekday")
    case "Saturday" | "Sunday":
        print("Weekend!")
    case _:
        print("Invalid day")

Output:

Weekend!

Matching Sequences

Match-case can unpack lists and tuples:

point = (0, 5)

match point:
    case (0, 0):
        print("Origin")
    case (x, 0):
        print(f"On x-axis at x={x}")
    case (0, y):
        print(f"On y-axis at y={y}")
    case (x, y):
        print(f"Point at ({x}, {y})")

Output:

On y-axis at y=5

Notice how x and y are capture variables — they capture the actual values from the data.

Matching Mappings (Dictionaries)

action = {"type": "login", "user": "alice"}

match action:
    case {"type": "login", "user": username}:
        print(f"Logging in user: {username}")
    case {"type": "logout", "user": username}:
        print(f"Logging out user: {username}")
    case {"type": "signup"}:
        print("New user signup")
    case _:
        print("Unknown action")

Output:

Logging in user: alice

Dictionary matching checks that the specified keys exist — extra keys are allowed.

Guard Conditions

Add if clauses to add extra checks:

point = (3, 4)

match point:
    case (x, y) if x == y:
        print(f"On diagonal at ({x}, {y})")
    case (x, y) if x > 0 and y > 0:
        print(f"First quadrant: ({x}, {y})")
    case (x, y):
        print(f"Other: ({x}, {y})")

Output:

First quadrant: (3, 4)

Wildcard Pattern

The _ wildcard matches anything without binding a name:

data = [1, 2, 3, 4, 5]

match data:
    case [first, *rest]:
        print(f"First: {first}, Rest: {rest}")

Output:

First: 1, Rest: [2, 3, 4, 5]
# Star pattern with wildcard
match data:
    case [first, _, _, _, last]:
        print(f"First: {first}, Last: {last}")

Output:

First: 1, Last: 5

match-case vs if-elif

Feature match-case if-elif
Simple value checks Cleaner Work fine
Pattern destructuring Built-in Requires manual unpacking
Multiple values case A \| B: if x == A or x == B:
Guard conditions case X if cond: Natural
Python version 3.10+ All versions
Complex expressions Limited Full flexibility

Use match-case when:

  • You’re checking a value against multiple fixed options
  • You need to destructure data (sequences, mappings)
  • You want clean, readable branching

Use if-elif when:

  • You need complex conditions (ranges, function calls)
  • You need to support Python < 3.10
  • Logic doesn’t fit a pattern-matching model

Practical Example: Command Parser

def handle_command(parts):
    match parts:
        case ["quit"]:
            return "Exiting..."
        case ["hello", name]:
            return f"Hello, {name}!"
        case ["add", x, y]:
            return f"Result: {int(x) + int(y)}"
        case ["help"]:
            return "Commands: quit, hello <name>, add <x> <y>"
        case _:
            return f"Unknown command: {' '.join(parts)}"

# Test
print(handle_command(["hello", "Alice"]))  # Hello, Alice!
print(handle_command(["add", "3", "5"]))   # Result: 8
print(handle_command(["quit"]))            # Exiting...
print(handle_command(["fly"]))             # Unknown command: fly

Summary

  • match-case is Python 3.10+’s structural pattern matching
  • Use _ as the wildcard (default/catch-all) pattern
  • Match literals, sequences (lists/tuples), and mappings (dicts)
  • Use | to match multiple values in one case
  • Add guard conditions with if after the pattern
  • Capture variables extract values from the matched data
  • When in doubt, if-elif works everywhere and is more familiar

Next up: Truthy & Falsy Values →

Updated: