Introduction

Python 3.10 introduced structural pattern matching (match-case statements), a powerful way to simplify conditional logic and improve code readability. Inspired by switch-case statements in other languages, structural pattern matching extends Python’s capabilities to match complex data structures like tuples, lists, dictionaries, and custom objects.

In this guide, we’ll explore PEP 634, learn how match-case works, and see real-world use cases with advanced techniques.


Why Use Structural Pattern Matching?

Improves readability compared to nested if-elif-else chains
Supports complex data structures like lists, tuples, and dicts
Enables powerful pattern-based dispatching
Optimized for performance in Python’s internals


1. Basic Syntax of match-case

Here’s the simplest form of structural pattern matching:

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

print(http_status(200))  # OK  
print(http_status(404))  # Not Found  
print(http_status(503))  # Unknown Status  

✔ Uses case _: as a default case, similar to else in if-elif-else statements.


2. Matching Tuples and Lists

Pattern matching extends beyond simple values—it works with tuples and lists:

def process_coordinates(point):  
match point:  
case (0, 0):  
return "Origin"  
case (x, 0):  
return f"X-axis at {x}"  
case (0, y):  
return f"Y-axis at {y}"  
case (x, y):  
return f"Point at ({x}, {y})"  
case _:  
return "Invalid input"

print(process_coordinates((10, 0)))   # X-axis at 10  
print(process_coordinates((0, 20)))   # Y-axis at 20  
print(process_coordinates((5, 7)))    # Point at (5, 7)  

Unpacks values into variables (x, y) directly inside the match-case.


3. Matching Dictionaries

You can match dictionaries with key-value patterns:

def identify_user(user):  
match user:  
case {"role": "admin", "name": name}:  
return f"Admin: {name}"  
case {"role": "guest"}:  
return "Guest User"  
case {"role": role}:  
return f"User Role: {role}"  
case _:  
return "Unknown User"

print(identify_user({"role": "admin", "name": "Alice"}))  # Admin: Alice  
print(identify_user({"role": "guest"}))                   # Guest User  
print(identify_user({"role": "editor"}))                  # User Role: editor  

Extracts dictionary values dynamically using {"key": variable} syntax.


4. Matching Custom Objects

match-case can work with custom objects using __match_args__:

class User:  
__match_args__ = ("name", "role")

    def __init__(self, name, role):  
        self.name = name  
        self.role = role  

def check_user(user):  
match user:  
case User(name, "admin"):  
return f"Admin: {name}"  
case User(name, role):  
return f"User: {name}, Role: {role}"  
case _:  
return "Unknown User"

u1 = User("Alice", "admin")  
u2 = User("Bob", "editor")

print(check_user(u1))  # Admin: Alice  
print(check_user(u2))  # User: Bob, Role: editor  

✔ Uses __match_args__ to define matchable attributes in the class.


5. Guard Conditions in match-case

You can add conditional checks inside cases:

def categorize_number(n):  
match n:  
case n if n % 2 == 0:  
return "Even number"  
case n if n % 2 != 0:  
return "Odd number"  
case _:  
return "Not a number"

print(categorize_number(10))  # Even number  
print(categorize_number(7))   # Odd number  

✔ Uses case value if condition: to filter matches dynamically.


6. Real-World Use Case: Parsing API Responses

Pattern matching is great for handling API responses:

def process_api_response(response):  
match response:  
case {"status": 200, "data": data}:  
return f"Success: {data}"  
case {"status": 404}:  
return "Error: Not Found"  
case {"status": 500, "error": msg}:  
return f"Server Error: {msg}"  
case _:  
return "Unknown Response"

response = {"status": 200, "data": {"user": "Alice"}}  
print(process_api_response(response))  # Success: {'user': 'Alice'}  

Extracts structured data without excessive if-else checks.


Best Practices for Using match-case

Use structured matching for better readability
Always include a wildcard case (_) to handle unexpected inputs
Use guards (case value if condition:) to add extra logic
Prefer dictionary matching for handling structured data
Leverage custom objects to match class instances cleanly


Conclusion

Python’s structural pattern matching (PEP 634) provides a powerful, expressive, and efficient way to handle conditional logic. Whether working with tuples, lists, dictionaries, or objects, match-case improves readability and reduces complex branching logic.

🚀 Start using pattern matching today and write cleaner, more maintainable Python code!