SythraOpen app

The match-case Statement in Python (Python's Switch)

Python 3.10 introduced match/case as a cleaner alternative to long if/elif chains for checking one value against many possibilities, with case _: as the required default case for anything unmatched.

Sythra

9 min read

XLinkedIn
The match-case Statement in Python (Python's Switch) — cover illustration

Many programming languages have something called a switch statement — a tool for checking one value against a whole list of possible cases and running different code depending on which one matches. For a very long time, Python did not have this at all; programmers just used if/elif/else chains. Starting in Python 3.10, Python added its own version: match/case.

This page covers both approaches, and — most importantly — how to handle the situation where none of your cases match.

What you will learn

  • How to simulate a switch statement with if/elif/else
  • The modern match/case syntax (Python 3.10+)
  • Matching multiple values in one case with |
  • Why a default case is not optional in practice
  • Connecting cases to functions, including dictionary dispatch

The old-school way: simulating "switch" with if/elif/else

Before match/case existed, here's how every Python programmer handled a "check one value against several options" situation:

day = 4

if day == 1:
    print("Monday")
elif day == 2:
    print("Tuesday")
elif day == 3:
    print("Wednesday")
elif day == 5:
    print("Friday")
else:
    print("Unknown day")

Notice there's no elif day == 4: here, on purpose. So what happens when day is 4? Python checks each condition top to bottom, finds none of them match, and falls all the way through to the final else: block. That else is your default case — the safety net that catches anything you didn't specifically plan for.

The modern way: match and case

Python 3.10 introduced a cleaner, more readable tool for exactly this situation: the match statement, paired with one or more case blocks.

day = 4

match day:
    case 1:
        print("Monday")
    case 2:
        print("Tuesday")
    case 3:
        print("Wednesday")
    case 5:
        print("Friday")
    case _:
        print("Unknown day")
  • match day: — "take the value stored in day, and compare it against each case below, top to bottom"
  • case 1: — "if day equals 1, run this block", and so on for each case
  • case _: — the special default case. The underscore _ is a wildcard matching anything not already caught by an earlier case; it must always go last

Run this with day = 4 and you'll get Unknown day printed, because there's no case 4: anywhere above it, so Python falls through to the wildcard case _: at the bottom — the exact same idea as the else block above.

Matching multiple values in one case

Sometimes you want several different values to all trigger the same response. Group them together in a single case using the | symbol (meaning "or" in this context):

day = 6

match day:
    case 1 | 2 | 3 | 4 | 5:
        print("Weekday")
    case 6 | 7:
        print("Weekend")
    case _:
        print("Not a valid day")

Here, case 6 | 7: means "if day is 6, OR if day is 7, run this block" — saving you from writing five nearly-identical case lines to print the same message five times.

The default case is not optional in practice

Technically, Python will let you write a match statement, or an if/elif chain, with no default case at all:

match day:
    case 1:
        print("Monday")
    case 2:
        print("Tuesday")

This runs perfectly fine — right up until someone passes in a value you didn't plan for, like day = 4. When that happens, nothing matches, nothing prints, and nothing crashes either. The program just quietly does nothing and moves on. This is called a silent failure, and it's one of the sneakiest kinds of bugs, because there's no error message to tell you something went wrong.

This is exactly why the golden habit of this page is: every switch-style decision should end with a default case — whether that's else: in an if chain, or case _: in a match statement. Think of it as a permanent safety net underneath your decision-making code.

Connecting cases to functions

So far, each case has just printed a short message. In real programs, you usually want each case to do something more substantial — the cleanest way is to write a separate function for each case, and have your match simply decide which function to call.

def handle_monday():
    print("Starting the work week — let's go!")

def handle_tuesday():
    print("Tuesday grind.")

def handle_friday():
    print("Almost the weekend!")

def handle_unknown_day():
    print("That's not a day I recognize.")


day = 4

match day:
    case 1:
        handle_monday()
    case 2:
        handle_tuesday()
    case 5:
        handle_friday()
    case _:
        handle_unknown_day()

Instead of cramming all the logic for "Monday" directly inside case 1:, we wrote a dedicated function handle_monday(), and the case block's only job is to call it. Since day = 4 matches nothing above it, Python falls through to case _:, which calls handle_unknown_day(). This keeps each piece of logic small, named, and easy to find later.

An even cleaner trick: dictionary dispatch

There's a popular pattern in Python for exactly this "pick a function based on a value" situation, which doesn't even need match or if/elif at all — it uses a dictionary to directly map each case to its matching function:

def handle_monday():
    print("Starting the work week — let's go!")

def handle_tuesday():
    print("Tuesday grind.")

def handle_friday():
    print("Almost the weekend!")

def handle_unknown_day():
    print("That's not a day I recognize.")


day_functions = {
    1: handle_monday,
    2: handle_tuesday,
    5: handle_friday,
}

day = 4

# .get() looks up day_functions[4], finds nothing, and uses
# handle_unknown_day as the fallback default instead of crashing
chosen_function = day_functions.get(day, handle_unknown_day)
chosen_function()

Notice we wrote handle_monday, not handle_monday()no parentheses. Without parentheses, we're referring to the function itself, like a tool sitting in a toolbox; with parentheses, we'd be calling it immediately. The dictionary stores the tools themselves, and we only "use" one once we've decided exactly which one we need.

The real magic is in .get(day, handle_unknown_day). This dictionary method tries to look up day (which is 4) inside day_functions; since there's no key 4, instead of raising an error, .get() quietly returns the second argument — our default function handle_unknown_day — exactly like case _: or else: did earlier, just written in a completely different style. This pattern is extremely popular in real, professional Python code, especially with many possible cases, because it avoids a long wall of case or elif lines.

Common mistakes

  • Forgetting the default case (else: or case _:) and getting a silent failure on unexpected input
  • Putting case _: anywhere except last — Python checks cases in order and stops at the first match
  • Writing handle_monday() with parentheses inside a dictionary meant to store the function itself
  • Assuming match/case is available in Python versions before 3.10

Common questions

Does Python have a switch statement?

Python does not have a traditional switch statement like C or Java. For most of Python's history, developers used if/elif/else chains instead. Python 3.10 introduced match/case, which serves a similar purpose.

What Python version added match-case?

The match statement (structural pattern matching) was introduced in Python 3.10. It is not available in earlier Python versions.

What does case _: mean in Python?

case _: is the wildcard default case in a match statement. The underscore matches anything not already caught by an earlier case, and must always be placed last since Python checks cases in order.

How do you match multiple values in one case?

Use the | (or) symbol inside a single case, like case 1 | 2 | 3:, which runs that block if the matched value is 1, 2, or 3.

What happens if no case matches and there's no default case?

If no case matches and there's no case _: default, the match statement does nothing at all — no error, no output. This silent failure can hide bugs, so a default case is considered essential in practice.

What is dictionary dispatch in Python?

Dictionary dispatch maps values to functions in a dictionary, then uses dict.get(key, default_function) to look up and call the matching function, falling back to a default if the key isn't found — an alternative to a long match or if/elif chain.

Explore

Related topics

Keep going — these sit next to this concept in a real learning path.

Browse all python explainers →