Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Python Dictionary

  1. Home
  2. Python Dictionary
  3. match / case (Pattern Matching)

match / case (Pattern Matching)

Python's match statement, added in Python 3.10, is a structural pattern matching syntax. Python 3.10 or later is required; this syntax is not available in Python 3.9 or earlier. It branches based on the structure or content of a value and can be more readable than a chain of if/elif/else. It supports literal, sequence, mapping, and class pattern matching, and can be combined with guard conditions (if clauses) and wildcards (_) for flexible branching. In Python 3.9 or earlier, if/elif chains or dictionary mapping can be used as alternatives.

Syntax

# Basic syntax
match subject:
    case pattern1:
        # code when pattern1 matches
    case pattern2:
        # code when pattern2 matches
    case _:
        # wildcard: runs when no other pattern matches

# Guard condition (if clause)
match subject:
    case pattern if condition:
        # code when pattern matches and condition is True

# OR pattern (combine multiple patterns with |)
match subject:
    case pattern_a | pattern_b:
        # code when either pattern matches

# Sequence pattern (branch on list/tuple structure)
match subject:
    case [elem1, elem2]:
        # matches a sequence of exactly 2 elements
    case [first, *rest]:
        # captures first element and remaining elements

# Mapping pattern (branch on dictionary keys)
match subject:
    case {"key": variable}:
        # matches a dict containing the specified key

# Class pattern (branch on object type and attributes)
match subject:
    case ClassName(attr=variable):
        # matches on type and attribute value

Keywords and Syntax

SyntaxNotes
match subject:Starts pattern matching. Checks the subject against each case pattern in order.
case pattern:Defines a block to run when the pattern matches the subject. Only the first matching case runs.
case _:Wildcard pattern. Runs when no other pattern matches. Equivalent to else in if/elif/else.
case pattern if condition:Guard condition. Evaluates the condition after the pattern matches; runs only when both are true.
case pattern_a | pattern_b:OR pattern. Runs when either pattern matches.
case [elem1, elem2]:Sequence pattern. Matches a list or tuple by length and element values.
case [first, *rest]:Star pattern. Binds the first element to a variable and captures the rest as a list.
case {"key": variable}:Mapping pattern. Matches a dict containing the specified key and binds the value to a variable.
case ClassName(attr=variable):Class pattern. Matches on object type and attribute values.

Sample Code

The basics of literal patterns. Branches based on whether a value equals a specific constant. This sample uses the Steins;Gate worldline concept.

literal_match.py
# Display a message based on the worldline ID.
# Literal pattern: write values directly in the case clause.
def describe_worldline(line_id):
    match line_id:
        case 0:
            return "Alpha worldline — the convergence where Suzuha cannot return to the past"
        case 1:
            return "Beta worldline — the convergence where Kurisu dies"
        case 2:
            return "Steins;Gate worldline — the only point where all tragedies are avoided"
        case _:
            # Runs when no other case matches (wildcard).
            return "Unknown worldline"

print(describe_worldline(0))
print(describe_worldline(2))
print(describe_worldline(99))
python3 literal_match.py
Alpha worldline — the convergence where Suzuha cannot return to the past
Steins;Gate worldline — the only point where all tragedies are avoided
Unknown worldline

Using OR patterns (|) to group multiple values into one case. Eliminates repetition when similar conditions apply.

or_pattern.py
# Determine permissions based on lab member role.
# Listing patterns with | means the block runs if either matches.
def get_permission(role):
    match role:
        case "Assistant" | "Future Gadget Lab Director":
            # Group multiple values with OR.
            return "Full access to experimental equipment"
        case "Lab Member" | "Collaborator":
            return "Read-only access"
        case _:
            return "No access"

print(get_permission("Future Gadget Lab Director"))   # Okabe Rintaro's title
print(get_permission("Lab Member"))
print(get_permission("Visitor"))
python3 or_pattern.py
Full access to experimental equipment
Read-only access
No access

Adding further conditions to pattern matching with guard conditions (if clauses). Useful for range checks that cannot be expressed with literals alone.

guard_match.py
# Classify worldline divergence.
# Guard condition: written as case pattern if condition.
def classify_divergence(divergence):
    match divergence:
        case d if d >= 1.048596:
            # Bind the value to d, then evaluate the guard condition.
            return f"Steins;Gate worldline ({d:.6f})"
        case d if 1.0 <= d < 1.048596:
            return f"Beta worldline group ({d:.6f})"
        case d if 0.0 <= d < 1.0:
            return f"Alpha worldline group ({d:.6f})"
        case _:
            return "Unmeasurable"

print(classify_divergence(1.048596))
print(classify_divergence(1.000000))
print(classify_divergence(0.571024))
python3 guard_match.py
Steins;Gate worldline (1.048596)
Beta worldline group (1.000000)
Alpha worldline group (0.571024)

Using sequence patterns to match the structure of lists and tuples. Different processing for different numbers or arrangements of elements.

sequence_match.py
# Change processing based on the structure of a D-Mail recipient list.
# Sequence pattern: written as case [elem1, elem2, ...].
def process_dmail(recipients):
    match recipients:
        case []:
            # Matches a sequence with zero elements.
            return "No recipients specified"
        case [single]:
            # Matches a sequence with one element and binds its value.
            return f"Single send: to {single}"
        case [first, second]:
            # Matches a sequence with exactly two elements.
            return f"Two recipients: {first} and {second}"
        case [first, *rest]:
            # Star pattern: bind first to first, remaining to rest.
            return f"Broadcast: {first} and {len(rest)} more"

print(process_dmail([]))
print(process_dmail(["Makise Kurisu"]))
print(process_dmail(["Okabe Rintaro", "Shiina Mayuri"]))
print(process_dmail(["Okabe Rintaro", "Shiina Mayuri", "Hashida Itaru", "Kiryu Moeka"]))
python3 sequence_match.py
No recipients specified
Single send: to Makise Kurisu
Two recipients: Okabe Rintaro and Shiina Mayuri
Broadcast: Okabe Rintaro and 3 more

Using mapping patterns to match dictionary keys. Well suited for processing dictionaries with variable structure such as API responses.

mapping_match.py
# Parse a dictionary representing the state of a time machine.
# Mapping pattern: written as case {"key": variable}.
# Matches even if the dict has extra keys (exact match is not required).
def analyze_timemachine(status):
    match status:
        case {"mode": "travel", "destination": dest, "passenger": passenger}:
            # Matches when all three keys are present.
            return f"{passenger} traveling to {dest}"
        case {"mode": "standby", "location": loc}:
            return f"Standby at: {loc}"
        case {"error": code}:
            # Matches when the error key is present.
            return f"Error code: {code}"
        case _:
            return "Unknown state"

print(analyze_timemachine({"mode": "travel", "destination": "2010-07-28", "passenger": "Okabe Rintaro"}))
print(analyze_timemachine({"mode": "standby", "location": "Future Gadget Lab"}))
print(analyze_timemachine({"error": "E42", "detail": "Divergence exceeded"}))
python3 mapping_match.py
Okabe Rintaro traveling to 2010-07-28
Standby at: Future Gadget Lab
Error code: E42

Using class patterns to match an object's type and attributes. Readability improves when combined with dataclasses.

class_match.py
from dataclasses import dataclass

# Define data classes representing lab member events.
@dataclass
class DmailEvent:
    sender: str
    content: str

@dataclass
class PhoneWaveEvent:
    operator: str
    target_date: str

@dataclass
class ReadSteinerEvent:
    observer: str

# Class pattern: written as case ClassName(attr=variable).
def handle_event(event):
    match event:
        case DmailEvent(sender=s, content=c):
            # Matches DmailEvent type and binds attribute values to s and c.
            return f"D-Mail received — sender: {s}, content: {c}"
        case PhoneWaveEvent(operator=op, target_date=d):
            return f"PhoneWave activated — operator: {op}, destination: {d}"
        case ReadSteinerEvent(observer=obs):
            return f"Reading Steiner triggered — observer: {obs}"
        case _:
            return "Unknown event"

print(handle_event(DmailEvent("Hashida Itaru", "Lotto 6 winning numbers")))
print(handle_event(PhoneWaveEvent("Okabe Rintaro", "2010-07-28")))
print(handle_event(ReadSteinerEvent("Okabe Rintaro")))
python3 class_match.py
D-Mail received — sender: Hashida Itaru, content: Lotto 6 winning numbers
PhoneWave activated — operator: Okabe Rintaro, destination: 2010-07-28
Reading Steiner triggered — observer: Okabe Rintaro

Common Mistakes

Common Mistake 1: Writing the wildcard _ first, matching everything

case _: is a wildcard that matches anything. Writing it first makes all subsequent case clauses unreachable. Always put the wildcard last.

ng_wildcard_first.py
def describe_worldline(line_id):
    match line_id:
        case _:
            return "Unknown worldline"   # Everything matches here
        case 0:
            return "Alpha worldline"     # Unreachable
        case 1:
            return "Beta worldline"      # Unreachable

print(describe_worldline(0))   # "Unknown worldline" (not what was intended)
print(describe_worldline(1))   # "Unknown worldline" (not what was intended)
python3 ng_wildcard_first.py
Unknown worldline
Unknown worldline
ok_wildcard_last.py
def describe_worldline(line_id):
    match line_id:
        case 0:
            return "Alpha worldline"
        case 1:
            return "Beta worldline"
        case _:
            return "Unknown worldline"   # Wildcard goes last.

print(describe_worldline(0))   # "Alpha worldline"
print(describe_worldline(1))   # "Beta worldline"
print(describe_worldline(99))  # "Unknown worldline"
python3 ok_wildcard_last.py
Alpha worldline
Beta worldline
Unknown worldline

Common Mistake 2: Confusing variable patterns with literal patterns

case x: does not compare against the variable x; it binds the subject to a new variable named x. Writing a constant's variable name in a case clause does not compare against it — it always matches and binds. Use a guard condition or an Enum for constant comparisons.

ng_variable_pattern.py
TARGET = "Steins;Gate"   # Defined as a constant

def check_worldline(name):
    match name:
        case TARGET:
            # Wrong: this does not compare against TARGET;
            # it binds name to a new variable called TARGET.
            return "Reached"   # Always matches
        case _:
            return "Not reached"   # Unreachable

print(check_worldline("Alpha worldline"))   # "Reached" (not intended)
python3 ng_variable_pattern.py
Reached
ok_guard_constant.py
TARGET = "Steins;Gate"

def check_worldline(name):
    match name:
        case n if n == TARGET:
            # Use a guard condition to compare against the constant.
            return "Reached"
        case _:
            return "Not reached"

print(check_worldline("Steins;Gate"))    # "Reached"
print(check_worldline("Alpha worldline"))  # "Not reached"
python3 ok_guard_constant.py
Reached
Not reached

Common Mistake 3: Using match on Python 3.9 or earlier causes SyntaxError

The match statement was added in Python 3.10. Running it on Python 3.9 or earlier causes a SyntaxError. Use if/elif/else when compatibility with older versions is required.

ng_old_python.py
# Running on Python 3.9 or earlier causes SyntaxError.
def describe(line_id):
    match line_id:
        case 0:
            return "Alpha worldline"
        case _:
            return "Unknown worldline"
python3 ng_old_python.py
  File "ng_old_python.py", line 3
    match line_id:
          ^^^^^^^^
SyntaxError: invalid syntax
ok_if_elif.py
# Use if/elif/else when compatibility with Python 3.9 or earlier is needed.
def describe(line_id):
    if line_id == 0:
        return "Alpha worldline"
    elif line_id == 1:
        return "Beta worldline"
    else:
        return "Unknown worldline"

print(describe(0))
print(describe(99))
python3 ok_if_elif.py
Alpha worldline
Unknown worldline

Notes

The match statement is not a replacement for if/elif/else; it is a syntax for branching based on the "structure" of a value. Because you can write the shape of a dict, list, or object directly in the pattern, it is particularly powerful for parsing complex nested data or dispatch processing that varies by type. For simple literal branching, if / elif / else is often sufficient, so match is worth choosing when its readability advantage is clear.

Each case is evaluated from top to bottom, and only the first matching case runs. Unlike the switch statement in other languages, there is no fall-through (where execution continues to the next case). Variables bound in a case clause are only in scope within that clause. Combining guard conditions (if clauses) with patterns allows you to add further filtering after a pattern matches; when the guard is false, evaluation moves to the next case.

The match statement is only available in Python 3.10 and later. When compatibility with earlier versions is required, use if/elif/else. For combining with dataclasses, see Class Definition and __init__.

If you find any errors or copyright issues, please .