
The Python match case statement is one of the most significant additions to the language in years. Introduced in Python 3.10 through PEP 634, it gives you a clean and expressive way to compare a value against multiple patterns and run the code block that matches. If you have worked with switch-case in languages like JavaScript, C, or Java, the Python match case statement will feel familiar — but it goes much further. Python's version supports structural pattern matching, meaning it can match not just literal values but also the shape and contents of sequences, dictionaries, and objects.
This guide walks through everything you need to know about the Python match case statement: the syntax, how each pattern type works, how to add conditions using guard clauses, and how to combine it all into a practical example.
The Python match case statement starts with the keyword match followed by the subject — the value you want to inspect. Each possible pattern goes inside a case block. Python evaluates the case blocks from top to bottom and runs the first one that matches the subject.
status = 200
match status:
case 200:
print("OK")
case 404:
print("Not Found")
case 500:
print("Internal Server Error")
Output
OK
The subject here is the variable status with a value of 200. Python checks each case in order. The first case block matches 200, so Python prints "OK" and skips the remaining case blocks. No break statement is needed — Python automatically stops after the first match.
The colon after each case value and after the match subject is required. Indentation works the same way it does in every other Python control structure: the case blocks are indented under match, and the code inside each case block is indented under that case.
The simplest use of the Python match case statement is matching against fixed, literal values like integers, strings, booleans, and None. You list each possible value in a separate case block.
day = "Monday"
match day:
case "Saturday":
print("It is the weekend")
case "Sunday":
print("It is the weekend")
case "Monday":
print("Start of the work week")
case "Friday":
print("Almost the weekend")
Output
Start of the work week
Python compares day against each string literal until it finds "Monday" and runs that block. The match is exact — Python uses equality comparison, not identity.
You can also match against integers, floats, booleans, and None in the same way:
score = None
match score:
case None:
print("No score recorded yet")
case 0:
print("Score is zero")
case 100:
print("Perfect score")
Output
No score recorded yet
Sometimes the same code block should run for more than one value. In the Python match case statement you can combine multiple patterns in a single case block using the pipe character, which acts as an OR operator.
command = "quit"
match command:
case "quit" | "exit" | "bye":
print("Exiting the program")
case "hello" | "hi":
print("Hello! How can I help you?")
case "help":
print("Showing help menu")
Output
Exiting the program
The case block with "quit" | "exit" | "bye" matches any of those three strings. When command is "quit", Python matches immediately and runs the print statement. This is much cleaner than writing three separate case blocks or chaining multiple conditions in an if statement.
The underscore is a special pattern in Python match case. It acts as a wildcard that matches any value. You place it in the last case block to handle everything that did not match any earlier pattern — essentially a default fallback.
http_code = 301
match http_code:
case 200:
print("Success")
case 404:
print("Not Found")
case 500:
print("Server Error")
case _:
print(f"Unrecognized status code: {http_code}")
Output
Unrecognized status code: 301
The wildcard pattern always goes last. If you place it earlier, Python will raise a SyntaxError because any pattern after an unconditional wildcard would be unreachable. The underscore does not bind the matched value to any variable — it is purely a throwaway pattern.
A capture pattern lets you bind the matched value to a variable name inside the case block. Instead of using an underscore, you use any valid variable name. Python assigns the subject value to that variable, making it available inside the block.
user_input = 42
match user_input:
case 0:
print("You entered zero")
case value:
print(f"You entered: {value}")
Output
You entered: 42
Here, value is a capture pattern. Since 42 does not match the literal 0, Python falls through to the capture pattern and binds 42 to value. You can then use value inside that case block like any other variable.
Capture patterns are particularly useful in sequence and mapping patterns where you want to extract specific elements while matching the structure.
One of the most powerful features of the Python match case statement is sequence pattern matching. You can match against lists and tuples by their structure — their length, the values at specific positions, or a combination of both.
point = (3, 7)
match point:
case (0, 0):
print("Origin point")
case (x, 0):
print(f"Point on the x-axis at {x}")
case (0, y):
print(f"Point on the y-axis at {y}")
case (x, y):
print(f"Point at x={x}, y={y}")
Output
Point at x=3, y=7
Python checks the structure: point is a tuple with two elements. It tries (0, 0) — no match. It tries (x, 0) — the second element is not 0, so no match. It tries (0, y) — the first element is not 0, so no match. It reaches (x, y) which matches any two-element tuple and captures both values.
You can also use the star pattern to capture a variable number of elements from a sequence:
numbers = [1, 2, 3, 4, 5]
match numbers:
case []:
print("Empty list")
case [x]:
print(f"Single element: {x}")
case [first, *rest]:
print(f"First: {first}, remaining: {rest}")
Output
First: 1, remaining: [2, 3, 4, 5]
The star pattern in the Python match case statement works similarly to unpacking with an asterisk in assignment expressions. It collects all remaining elements into a list.
Python match case also supports matching dictionaries by their keys and structure. A mapping pattern lets you check whether a dictionary contains certain keys and optionally capture their values.
config = {"host": "localhost", "port": 8080}
match config:
case {"host": host, "port": port}:
print(f"Connecting to {host} on port {port}")
case {"host": host}:
print(f"Connecting to {host} using default port")
case {}:
print("Empty configuration")
Output
Connecting to localhost on port 8080
The mapping pattern matches if the dictionary contains at least the specified keys. Extra keys in the dictionary are ignored unless you add a double-star pattern to capture them. The values at those keys are captured into variables: host gets "localhost" and port gets 8080.
response = {"status": 200, "body": "Hello", "content_type": "text/plain"}
match response:
case {"status": 200, "body": body, **extra}:
print(f"Success: {body}")
print(f"Extra fields: {extra}")
case {"status": 404}:
print("Not found")
Output
Success: Hello
Extra fields: {'content_type': 'text/plain'}
The double-star pattern captures all remaining keys in the dictionary into a dictionary variable called extra.
A guard clause adds an extra condition to a case block using the if keyword after the pattern. Python only runs a case block if both the pattern matches and the guard condition evaluates to True.
age = 17
match age:
case n if n < 0:
print("Invalid age")
case n if n < 18:
print(f"Minor: {n} years old")
case n if n >= 18:
print(f"Adult: {n} years old")
Output
Minor: 17 years old
The capture pattern n binds the value of age, and then the guard condition if n < 18 is checked. Since 17 is less than 18, Python runs that block. Guard clauses let you express complex matching conditions that go beyond pure structural comparison.
You can use guard clauses together with sequence patterns:
coordinates = (10, -5)
match coordinates:
case (x, y) if x > 0 and y > 0:
print("First quadrant")
case (x, y) if x < 0 and y > 0:
print("Second quadrant")
case (x, y) if x < 0 and y < 0:
print("Third quadrant")
case (x, y) if x > 0 and y < 0:
print("Fourth quadrant")
case _:
print("On an axis")
Output
Fourth quadrant
Python match case can also match against instances of classes by checking the class type and optionally matching against its attributes. This uses positional or keyword arguments in the pattern.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def describe_point(p):
match p:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"On y-axis at y={y}")
case Point(x=x, y=0):
print(f"On x-axis at x={x}")
case Point(x=x, y=y):
print(f"Point at ({x}, {y})")
describe_point(Point(0, 5))
describe_point(Point(3, 0))
describe_point(Point(2, 4))
Output
On y-axis at y=5
On x-axis at x=3
Point at (2, 4)
The class pattern checks both that the subject is an instance of the specified class and that the keyword arguments match the object's attributes. Python uses keyword attribute names by default, but you can also enable positional matching using the special class variable match_args.
This example brings together literal patterns, OR patterns, sequence patterns, guard clauses, and a wildcard to build a simple command dispatcher for a text-based application.
def process_command(command):
match command:
case ["quit"] | ["exit"]:
print("Goodbye! Exiting the application.")
case ["add", item]:
print(f"Adding item: {item}")
case ["remove", item]:
print(f"Removing item: {item}")
case ["move", item, destination] if destination in ("top", "bottom"):
print(f"Moving '{item}' to the {destination} of the list")
case ["move", item, destination]:
print(f"Unknown destination '{destination}' for item '{item}'")
case ["search", *keywords]:
print(f"Searching for: {', '.join(keywords)}")
case ["help"]:
print("Available commands: add, remove, move, search, quit")
case _:
print(f"Unrecognized command: {command}")
process_command(["add", "notebook"])
process_command(["remove", "pen"])
process_command(["move", "eraser", "top"])
process_command(["move", "ruler", "middle"])
process_command(["search", "blue", "pen", "large"])
process_command(["help"])
process_command(["quit"])
process_command(["fly"])
Output
Adding item: notebook
Removing item: pen
Moving 'eraser' to the top of the list
Unknown destination 'middle' for item 'ruler'
Searching for: blue, pen, large
Available commands: add, remove, move, search, quit
Goodbye! Exiting the application.
Unrecognized command: ['fly']
Each command arrives as a list. The Python match case statement checks its structure: a one-element list for quit and help, a two-element list for add and remove, a three-element list with a guard for move, a variable-length list for search, and a wildcard for anything unrecognized. The guard clause on the move pattern filters valid destinations separately from invalid ones, so each case handles exactly one scenario with no overlap or ambiguity.
You can read the full specification for Python structural pattern matching in the official Python documentation.