Python > Evolving Python > Python Versions > New Features in Recent Python Versions

Structural Pattern Matching in Python 3.10

Python 3.10 introduced structural pattern matching, a powerful feature that allows you to match the structure of data against patterns. This is similar to switch statements in other languages but much more expressive. It can handle different types of data, including sequences, mappings, and class instances. It drastically improves code readability when dealing with complex conditional logic based on data structure.

Basic Example: Matching a Point

This example defines a function process_point that takes a tuple (representing a point) as input. The match statement then compares the input tuple against several case patterns. If a pattern matches, the code block associated with that case is executed. The _ is a wildcard that matches anything, serving as a default case.

def process_point(point):
    match point:
        case (0, 0): # Matching a tuple with two 0s
            print("Origin")
        case (x, 0): # Matching a tuple where the second element is 0
            print(f"x={x}, on the x-axis")
        case (0, y): # Matching a tuple where the first element is 0
            print(f"y={y}, on the y-axis")
        case (x, y): # Matching any other tuple with two elements
            print(f"x={x}, y={y}")
        case _:
            print("Not a point")

process_point((0, 0))
process_point((5, 0))
process_point((0, 3))
process_point((1, 2))
process_point(5)

Matching Data Classes

This demonstrates pattern matching with data classes. We define a Color data class with red, green, and blue attributes. The match statement checks the attributes of a Color object. Note the use of if clauses within the case statements for more complex conditions (guard conditions).

from dataclasses import dataclass

@dataclass
class Color:
    red: int
    green: int
    blue: int

def describe_color(color):
    match color:
        case Color(red=255, green=0, blue=0): # Exact match
            print("Red")
        case Color(red=r, green=0, blue=b): # Partial match, capturing values
            print(f"Shade of red with blue component {b} and red component {r}")
        case Color(red=r, green=g, blue=b) if r == g == b:
            print("Gray color")
        case Color(red=r, green=g, blue=b): # Generic match
            print(f"RGB: {r}, {g}, {b}")


color1 = Color(255, 0, 0)
color2 = Color(200, 0, 50)
color3 = Color(128, 128, 128)
color4 = Color(10, 20, 30)
describe_color(color1)
describe_color(color2)
describe_color(color3)
describe_color(color4)

Concepts Behind the Snippet

Structural pattern matching deconstructs data to match against different patterns. These patterns can be literals, variables, sequences, or object attributes. The match keyword initiates the matching process, and the case keyword defines the individual patterns to check. The wildcard _ can be used as a catch-all. Guard clauses (if conditions within a case) enable additional filtering.

Real-Life Use Case

Pattern matching is incredibly useful when parsing complex data formats like JSON, XML, or network protocols. Imagine you're building an API that receives different types of messages. Pattern matching can elegantly handle the different message structures and route them to the appropriate handlers.

Best Practices

Always include a default case (using _) to handle unexpected data structures. Order your case statements from most specific to least specific. Use guard clauses judiciously to avoid overly complex patterns. Consider using pattern matching when you find yourself writing deeply nested if-elif-else statements based on data structure.

When to use them

Use structural pattern matching when you need to handle multiple possible data structures or types in a clear and concise way. It improves readability compared to nested if-else statements, especially when dealing with complex data.

Interview Tip

Be prepared to explain the benefits of structural pattern matching over traditional if-else chains. Demonstrate your understanding of different pattern types (literals, variables, sequences, objects) and guard clauses.

FAQ

  • What is the underscore '_' in a match statement?

    The underscore '_' is a wildcard. It matches anything and is typically used as the default case in a match statement.
  • Can I use pattern matching with custom classes that are not data classes?

    Yes, you can. However, you'll need to define a __match_args__ attribute in your class. This attribute specifies the order in which the class's attributes should be matched. See the Python documentation for more details.