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 pattern matching.

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).

Pattern Matching Syntax

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 see 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, the corresponding text is returned
  • Otherwise, it returns “Other value”.

Matching with Data Structures

Pattern matching in Python is particularly useful when used with more complex data structures (like lists, dictionaries, and tuples). Let’s look at some more advanced examples.

Lists and Tuples

In this example, we will see how to recognize patterns in lists or tuples with 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 make a default case if none of the previous ones are met

Dictionaries

We can also apply Pattern Matching to dictionaries, to search for those that meet a certain condition. 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 containing 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.