Python Switch Case: match case Statement (With Examples)

Python has a switch case statement: since Python 3.10 it’s called match, and each branch is a case. The value is checked against each case in order, and case _ is the default:

match command:
    case "start":
        print("Starting")
    case "stop" | "quit":
        print("Stopping")
    case _:
        print("Unknown command")

Coming from Java, C# or VBA’s Select Case? The ideas carry over, with a few differences that catch people out. The output below is from Python 3.14.7.

Flow diagram of the Python match case statement where the first matching case runs and case underscore is the default
Python checks each case in order, runs the first one that matches and skips the rest.

Python switch case with match: a first example

Here’s a small function that turns HTTP status codes into text:

def http_status(code):
    match code:
        case 200:
            return "OK"
        case 301 | 302:
            return "Redirect"
        case 404:
            return "Not Found"
        case _:
            return "Something else"

for code in (200, 302, 404, 500):
    print(code, "->", http_status(code))

Output:

200 -> OK
302 -> Redirect
404 -> Not Found
500 -> Something else
Command Prompt showing a Python switch case using match case to map HTTP status codes to names
Each code goes to the first case that matches; 500 falls through to case _.

match code: names the value to test, and each case gives a pattern. The first pattern that fits wins, its block runs, and the rest are skipped.

case 301 | 302: matches either value, which is how you handle several values at once. case _: matches anything, so it plays the role of default.

Does Python have a switch statement?

It does now, but only since Python 3.10. Before that, match was simply a syntax error:

import sys

status = 404
match status:
    case 404:
        print("matched 404 on Python", sys.version.split()[0])

Output:

  File "switch_version.py", line 4
    match status:
          ^
SyntaxError: invalid syntax
matched 404 on Python 3.14.7
Command Prompt showing Python match case raising SyntaxError on Python 3.8 and running on Python 3.14
The same file fails on Python 3.8 and runs on current Python.

I ran the same file on Python 3.8 and on current Python. 3.8 stops at match status: with SyntaxError: invalid syntax, and 3.9 does the same.

So if a teammate gets that error, the fix is usually their Python version, not the code. Checking which Python version you have takes one command.

If you’re coming from VBA or SQL, here’s how Select Case translates:

VBA / SQLPython match
Select Case statusmatch status:
Case 200case 200:
Case 301, 302case 301 | 302:
Case 90 To 100case s if 90 <= s <= 100:
Case Elsecase _:
CASE WHEN ... THEN ... END (SQL)match, or a conditional expression for one line

That history is why so many older tutorials say Python has no switch. It’s also why the dictionary approach further down is still worth knowing.

Match multiple values in one case

Join values with | to share one block. This is the Python answer to stacking several case labels in other languages:

def day_type(day):
    match day.lower():
        case "saturday" | "sunday":
            return "weekend"
        case "monday" | "tuesday" | "wednesday" | "thursday" | "friday":
            return "weekday"
        case _:
            return "not a day"

for day in ("Sunday", "wednesday", "Funday"):
    print(f"{day:<10} -> {day_type(day)}")

Output:

Sunday     -> weekend
wednesday  -> weekday
Funday     -> not a day

| means “or” inside a pattern. Calling .lower() before matching makes the comparison ignore capital letters, so Sunday and sunday both land in the weekend case.

There’s more on comparing text without caring about case in case-insensitive string comparisons.

A switch case driven by user input

Menus are the classic use. input() always returns a string, so match against strings, not numbers:

choice = input("Pick 1) balance  2) deposit  3) quit: ").strip()

match choice:
    case "1":
        print("Your balance is $1,250.00")
    case "2":
        print("How much would you like to deposit?")
    case "3" | "q" | "quit":
        print("Goodbye")
    case _:
        print(f"{choice!r} isn't an option")

Output:

Pick 1) balance  2) deposit  3) quit: How much would you like to deposit?
Command Prompt showing a Python switch case menu where the user types 2 and match case picks the deposit option
Typing 2 at the prompt runs the case "2" block.

The captured output above shows no 2, because typed input isn’t echoed there; the screenshot shows it at the prompt. It arrived as the text "2", so case "2" matched.

case "2" is the important part. A case 2: with a number would never match input, which is a common reason a menu seems to ignore every choice.

.strip() removes stray spaces, and case "3" | "q" | "quit": accepts several ways of saying the same thing.

The default case in a Python switch: case _

case _: catches everything the earlier cases didn’t. Leave it out, and nothing happens for unmatched values:

def describe(x):
    match x:
        case 1:
            return "one"
        case 2:
            return "two"

print(describe(1))
print(describe(9))        # no case matched and there's no case _

Output:

one
None

With no matching case and no case _, Python silently skips the whole match. Here the function then ends without a return, so you get None.

That’s rarely what you want, so I add case _: to almost every match, even if it only raises an error for values that should never happen.

Why a Python switch case needs no break

In C or Java, forgetting break makes execution fall into the next case. Python’s match never falls through:

def label(n):
    match n:
        case int():
            return "any integer"
        case 5:
            return "exactly five"     # never reached for 5: the first match wins

print("label(5) ->", label(5))
print()

seen = []
for n in range(10):
    match n:
        case 3:
            break                     # this leaves the for loop, not just the match
        case _:
            seen.append(n)
print("break inside match stopped the loop at:", seen)

Output:

label(5) -> any integer

break inside match stopped the loop at: [0, 1, 2]

case int() matched 5 first, so case 5 was never checked. Only one block ever runs, which means there’s nothing to break out of.

If you do write break inside a match that sits in a loop, it breaks the loop, as the second part shows. Order your cases from most specific to most general.

Match ranges and conditions with guards

A plain case compares one value. For ranges, add an if guard to the case:

def grade(score):
    match score:
        case s if s >= 90:
            return "A"
        case s if s >= 80:
            return "B"
        case s if s >= 70:
            return "C"
        case _:
            return "below C"

for score in (95, 84, 71, 50):
    print(score, "->", grade(score))

Output:

95 -> A
84 -> B
71 -> C
50 -> below C

case s if s >= 90: captures the value as s and only matches when the condition is true. The cases are still tried in order, so each one only needs its lower bound.

For a handful of ranges like this, an if/elif chain is just as clear. Guards shine when you combine them with the structural patterns below.

The bare-name trap: why case RED matches everything

This is the mistake almost everyone makes once. A plain variable name in a case doesn’t compare against that variable:

from enum import Enum

RED = "red"

def color_bare(c):
    match c:
        case RED:                # a bare name CAPTURES whatever c is
            return "is red"

print("bare name:  ", color_bare("blue"))

class Color(Enum):
    RED = "red"
    BLUE = "blue"

def color_dotted(c):
    match c:
        case Color.RED:          # a dotted name is compared by value
            return "is red"
        case Color.BLUE:
            return "is blue"
        case _:
            return "unknown"

print("dotted name:", color_dotted(Color.BLUE))
print()

code = """
def color(c):
    match c:
        case RED:
            return "red"
        case "blue":
            return "blue"
"""
try:
    compile(code, "<example>", "exec")
except SyntaxError as err:
    print("SyntaxError:", err.msg)

Output:

bare name:   is red
dotted name: is blue

SyntaxError: name capture 'RED' makes remaining patterns unreachable
Command Prompt showing the Python match case bare name capture trap and the fix with a dotted Enum name
A bare name captures any value; a dotted name like Color.RED is compared by value.

case RED: doesn’t mean “equals the constant RED”. It means “match anything and store it in a new variable called RED”, so "blue" was reported as red.

When other cases follow, Python spots it and refuses to run: name capture 'RED' makes remaining patterns unreachable. On its own, though, it matches silently.

The fix is a dotted name. Color.RED from an Enum, or constants.RED from a module, is compared by v