🎯 Pattern Matching
Pattern matching is Python's modern approach to handling complex decision scenarios. Introduced in Python 3.10, the match-case statement provides a powerful and elegant way to compare values against patterns, making complex conditional logic more readable and maintainable.
Think of pattern matching as a sophisticated switch statement that can match not just simple values, but also complex data structures, types, and conditions. It's particularly useful when you need to handle many different cases based on the structure or content of your data.
# Basic pattern matching example
def describe_animal(animal):
match animal:
case "dog":
return "Loyal companion"
case "cat":
return "Independent hunter"
case "bird":
return "Flying friend"
case _: # Default case
return "Unknown animal"
print(describe_animal("dog")) # Output: Loyal companion
print(describe_animal("fish")) # Output: Unknown animal
📝 Basic Match-Case Syntax
The match statement evaluates an expression and compares it against a series of case patterns. When a pattern matches, Python executes the corresponding code block. The underscore (_) serves as a wildcard that matches anything.
Unlike if-elif chains, match statements are designed specifically for pattern comparison and offer more sophisticated matching capabilities than simple equality checks.
# Basic match-case patterns with OR operator
def get_day_type(day):
match day:
case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
return "Weekday"
case "Saturday" | "Sunday":
return "Weekend"
case _:
return "Invalid day"
print(get_day_type("Monday")) # Output: Weekday
print(get_day_type("Saturday")) # Output: Weekend
print(get_day_type("Holiday")) # Output: Invalid day
🔍 Matching Values and Types
Pattern matching can match specific values, ranges, and even data types. This flexibility makes it powerful for handling different kinds of input data with appropriate responses using type conversion concepts.
You can combine value matching with type checking to create robust input validation and processing logic.
# Matching values and types with guards
def process_input(value):
match value:
case int() if value > 0:
return f"Positive integer: {value}"
case int() if value < 0:
return f"Negative integer: {value}"
case 0:
return "Zero"
case str() if len(value) > 0:
return f"Non-empty string: {value}"
case str():
return "Empty string"
case bool():
return f"Boolean: {value}"
case _:
return f"Other type: {type(value).__name__}"
print(process_input(42)) # Output: Positive integer: 42
print(process_input("hello")) # Output: Non-empty string: hello
print(process_input(True)) # Output: Boolean: True
print(process_input([1, 2, 3])) # Output: Other type: list
🎯 Quick Pattern Matching Practice
Let's practice using Python's match-case statements for pattern matching!
Hands-on Exercise
Practice using match-case statements to handle different values and patterns.
# Pattern Matching Practice - Number handler!
# Handle different numbers
number = 5
# TODO: Your code here: Use match-case to handle:
# 0: "Zero"
# 1: "One"
# 2: "Two"
# Any other number: "Other number"
Solution and Explanation 💡
Click to see the complete solution
# Pattern Matching Practice - Simple solution
# Handle different numbers
number = 5
match number:
case 0:
print("Zero")
case 1:
print("One")
case 2:
print("Two")
case _:
print("Other number")
Key Learning Points:
- 📌 match statement: Checks a value against multiple patterns
- 📌 case patterns: Each case handles a specific pattern
- 📌 Default case (_): Catches any unmatched values
- 📌 Python 3.10+: Pattern matching requires newer Python versions
🏗️ Matching Data Structures
One of pattern matching's most powerful features is the ability to match and destructure complex data structures like lists, tuples, and dictionaries. This makes it excellent for processing structured data.
Pattern matching can extract values from data structures while simultaneously checking their structure, combining validation and data extraction in a single operation.
# Matching data structures
def analyze_coordinates(point):
match point:
case [0, 0]:
return "Origin point"
case [x, 0]:
return f"On X-axis at {x}"
case [0, y]:
return f"On Y-axis at {y}"
case [x, y] if x == y:
return f"Diagonal point at ({x}, {y})"
case [x, y]:
return f"Point at ({x}, {y})"
case _:
return "Invalid coordinates"
print(analyze_coordinates([0, 0])) # Output: Origin point
print(analyze_coordinates([5, 0])) # Output: On X-axis at 5
print(analyze_coordinates([3, 3])) # Output: Diagonal point at (3, 3)
print(analyze_coordinates([2, 7])) # Output: Point at (2, 7)
🔄 Pattern Matching vs If-Elif
Understanding when to use pattern matching versus traditional if-elif chains helps you choose the right tool for each situation.
Feature | Pattern Matching | If-Elif Chains |
---|---|---|
Best for | Structural data comparison | Simple condition checking |
Syntax | match value: case pattern: | if condition: elif condition: |
Data Extraction | Built-in destructuring | Manual extraction needed |
Guard Conditions | case x if condition: | elif condition and other: |
Python Version | 3.10+ | All versions |
Readability | Clean for complex patterns | Better for simple conditions |
# Pattern matching vs if-elif comparison
def grade_with_match(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 "F"
def grade_with_elif(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "F"
# Both functions work the same way
print(grade_with_match(85)) # Output: B
print(grade_with_elif(85)) # Output: B
📊 Common Pattern Matching Patterns
There are several patterns you'll encounter frequently when working with pattern matching in real applications.
Pattern | Example | Use Case |
---|---|---|
OR Patterns | case "yes" | "y" | "true": | Multiple valid inputs |
Wildcard | case _: | Default case |
Guards | case x if x > 0: | Additional conditions |
List Destructuring | case [first, *rest]: | Processing sequences |
Dictionary Matching | case {"type": "user"}: | API response handling |
# Common pattern matching patterns
def handle_user_input(command):
match command.lower().split():
case ["quit"] | ["exit"] | ["q"]:
return "Goodbye!"
case ["help"] | ["h"]:
return "Available commands: save, load, quit"
case ["save", filename]:
return f"Saving to {filename}"
case ["load", filename]:
return f"Loading from {filename}"
case ["count", *numbers]:
total = sum(int(n) for n in numbers)
return f"Sum: {total}"
case _:
return "Unknown command"
print(handle_user_input("quit")) # Output: Goodbye!
print(handle_user_input("save data.txt")) # Output: Saving to data.txt
print(handle_user_input("count 1 2 3 4")) # Output: Sum: 10
✅ Pattern Matching Best Practices
Following best practices helps you write effective and maintainable pattern matching code.
📚 Key Takeaways
Test Your Knowledge
Test what you've learned about pattern matching in Python:
🚀 What's Next?
Pattern matching is a powerful tool for handling complex decision scenarios in modern Python code. While not always necessary, it shines when dealing with structured data and complex conditional logic.
Next, you'll learn about Repetition and Loops, which introduces the fundamental concept of repeating code execution. Loops often use the decision-making skills you've learned for controlling when to continue or stop.
Pattern matching works excellently with data structures, function parameters, and error handling scenarios.
Understanding pattern matching prepares you for advanced Python features and professional development practices.
Was this helpful?
Track Your Learning Progress
Sign in to bookmark tutorials and keep track of your learning journey.
Your progress is saved automatically as you read.