Language: EN

pattern-matching-python

Pattern Matching in Python

Pattern matching is a technique introduced in Python 3.10 that allows comparing a data structure with a given pattern and executing code based on the pattern match.

Unlike traditional if-else statements, pattern matching provides a more readable and concise way to handle different cases, especially when working with nested and complex data structures.

Syntax of Pattern Matching

The basic syntax of pattern matching in Python consists of the keyword match followed by an expression to be compared, and a case block to define the patterns to match.

Let’s look at a basic example of pattern matching using a simple data structure:

def analyze_data(data):
    match data:
        case 1:
            return "One"
        case 2:
            return "Two"
        case 3:
            return "Three"
        case _:
            return "Other value"

In this example:

  • The function analyze_data uses match to compare the value of data with the patterns defined in the case blocks.
  • If data is equal to 1, 2, or 3, it returns the corresponding text.
  • Otherwise, it returns “Other value”.

Matching with Data Structures

Pattern matching in Python is especially powerful when used with more complex data structures like lists, dictionaries, and tuples. Let’s see some more advanced examples.

Lists and Tuples

In this example, we’ll see how to recognize patterns in lists or tuples using Pattern Matching.

def analyze_list(lst):
    match lst:
        case [1, 2, 3]:
            return "Case 1: 1 to 3"
        case [1, *rest]:
            return f"Case 2: Starts with 1 and then {rest}"
        case _:
            return "Other type of list"

print(analyze_list([1, 2, 3]))  # Output: 'Case 1: 1 to 3'
print(analyze_list([1, 4, 5]))  # Output: 'Starts with 1 and then [4, 5]'
print(analyze_list([7, 8]))     # Output: 'Other type of list'

In this example:

  • The pattern [1, 2, 3] looks for exactly that list.
  • The pattern [1, *rest] uses the * operator to capture all remaining elements in a list after a specific element (in this case, 1).
  • The pattern _ is a “discard” and is used to create a default case if none of the previous ones are met.

Dictionaries

We can also apply Pattern Matching to dictionaries to look for those that meet certain conditions. For example:

def analyze_dictionary(dictionary):
    match dictionary:
        case {"name": name, "age": age}:
            return f"Case 1: Name: {name}, Age: {age}"
        case {"name": name}:
            return f"Case 2: Name: {name}"
        case _:
            return "Other type of dictionary"

print(analyze_dictionary({"name": "Ana", "age": 30}))
# Output: 'Case 1: Name: Ana, Age: 30'

print(analyze_dictionary({"name": "Luis"}))
# Output: 'Case 2: Name: Luis'
print(analyze_dictionary({"city": "Madrid"}))
# Output: Other type of dictionary

Here, the pattern {"name": name, "age": age} is used to match a dictionary that contains specific keys and capture their values.

Class Patterns

Pattern matching also allows working with class objects and checking if a class instance matches a certain pattern:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

def analyze_person(person):
    match person:
        case Person(name="Ana", age=30):
            return "Person Ana, 30 years old"
        case Person(name, age):
            return f"Person: {name}, Age: {age}"
        case _:
            return "Other type of object"

person1 = Person("Ana", 30)
person2 = Person("Luis", 25)

print(analyze_person(person1))  # Output: Person Ana, 30 years old
print(analyze_person(person2))  # Output: Person: Luis, Age: 25

In this case, match is used to check instances of the Person class and capture the attributes name and age.