Python 3.10 (released in 2021) introduced structural pattern matching via the match and case keywords — Python's version of the switch statement found in languages like C, Java, and JavaScript, but considerably more powerful. If you've ever written a long chain of elif statements that all compare the same variable against different fixed values, match/case is usually a cleaner way to express the same logic.

Basic Syntax: Matching Literal Values

def describe_status(code):
    match code:
        case 200:
            return "OK"
        case 404:
            return "Not Found"
        case 500:
            return "Server Error"
        case _:
            return "Unknown status"

print(describe_status(200))
print(describe_status(404))
print(describe_status(999))

Output:

OK
Not Found
Unknown status

Python checks each case from top to bottom and runs the first one that matches, exactly like elif does. The case _: at the end is the wildcard pattern — it matches anything, so it acts as the "default" case, equivalent to a final else. Without it, a value that doesn't match any case simply falls through and nothing runs.

Matching Multiple Values with |

You can combine several literal values into a single case using | (meaning "or"), avoiding repeated blocks for values that should be handled the same way:

def describe_day(day):
    match day:
        case "Saturday" | "Sunday":
            return "Weekend"
        case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
            return "Weekday"
        case _:
            return "Not a valid day"

print(describe_day("Saturday"))
print(describe_day("Tuesday"))

Output:

Weekend
Weekday

Beyond switch: Matching Structure, Not Just Values

What makes match more powerful than a traditional switch statement is that it can match the shape of a value — like unpacking a tuple or checking a dictionary's fields — not just a single literal. This is the "structural" in structural pattern matching.

def describe_point(point):
    match point:
        case (0, 0):
            return "Origin"
        case (0, y):
            return f"On the Y-axis at {y}"
        case (x, 0):
            return f"On the X-axis at {x}"
        case (x, y):
            return f"Point at ({x}, {y})"

print(describe_point((0, 0)))
print(describe_point((0, 5)))
print(describe_point((3, 4)))

Output:

Origin
On the Y-axis at 5
Point at (3, 4)

Here, case (0, y): both checks that the tuple's first element is 0 and binds whatever the second element is to a new variable y you can use inside that branch — a single pattern is doing both the condition check and a variable assignment at once.

match/case vs a Long elif Chain

Everything match/case does for simple literal matching, you could also write with an if/elif chain — and for just two or three branches, plain if/elif is often still the simpler choice. match starts paying off once you have many possible values to compare against the same variable, or once you need to match on structure (tuples, lists, or objects with certain attributes) rather than a single exact value — something a chain of equality checks can't express nearly as cleanly.