Начиная с Python 3.10, в язык была добавлена конструкция match-case (структурное сопоставление с образцом), которая предоставляет более мощный и выразительный способ обработки различных случаев по сравнению с традиционными цепочками if-elif-else.

Основной синтаксис

match выражение:
    case шаблон_1:
        # действия, если выражение соответствует шаблон_1
    case шаблон_2:
        # действия, если выражение соответствует шаблон_2
    case _:
        # действия по умолчанию (аналог else)

Типы шаблонов

Литеральные шаблоны:

case 1:
case "hello":
case True:

Шаблоны с переменными:

case x:
    print(f"Значение: {x}")

Шаблоны последовательностей (Sequence Patterns):

Базовые примеры:

def handle_sequence(seq):
    match seq:
        case [x, y, z]:
            print(f"Ровно три элемента: {x}, {y}, {z}")
        case [first, *rest]:
            print(f"Первый элемент: {first}, остальные: {rest}")
        case []:
            print("Пустая последовательность")
        case _:
            print("Не последовательность или другая структура")

handle_sequence([1, 2, 3])       # Ровно три элемента: 1, 2, 3
handle_sequence([1, 2])           # Первый элемент: 1, остальные: [2]
handle_sequence([])               # Пустая последовательность

Особенности:

*rest захватывает оставшиеся элементы (может быть пустым списком)

Можно использовать вложенные шаблоны:

case [x, [y, z]]:
    print(f"Вложенная структура: {x}, [{y}, {z}]")

Работает с любыми последовательностями, включая tuple:

case (x, y):
    print(f"Кортеж из двух элементов: {x}, {y}")

Шаблоны отображений (Mapping Patterns):

Базовые примеры:

def handle_dict(data):
    match data:
        case {"name": name, "age": age}:
            print(f"Пользователь {name}, возраст {age}")
        case {"command": cmd, **rest}:
            print(f"Команда: {cmd}, параметры: {rest}")
        case {}:
            print("Пустой словарь")
        case _:
            print("Не словарь или другая структура")

handle_dict({"name": "Alice", "age": 30})  # Пользователь Alice, возраст 30
handle_dict({"command": "run", "speed": 10})  # Команда: run, параметры: {'speed': 10}

Особенности:

**rest захватывает оставшиеся пары ключ-значение

Проверяется только наличие указанных ключей, остальные игнорируются

Можно проверять конкретные значения:

case {"status": 200, "data": data}:
    print(f"Успешный ответ: {data}")

Шаблоны классов(Class Patterns):

Используются для сопоставления с атрибутами объектов

Пример с классом Point:

class Point:
    __match_args__ = ('x', 'y')  # Определяет порядок атрибутов для сопоставления
    
    def __init__(self, x, y):
        self.x = x
        self.y = y

def handle_point(point):
    match point:
        case Point(0, 0):
            print("Точка в начале координат")
        case Point(x, 0):
            print(f"Точка на оси X: {x}")
        case Point(0, y):
            print(f"Точка на оси Y: {y}")
        case Point(x, y):
            print(f"Точка в координатах: ({x}, {y})")
        case _:
            print("Не точка")

handle_point(Point(0, 0))  # Точка в начале координат
handle_point(Point(5, 0))  # Точка на оси X: 5
handle_point(Point(3, 4))  # Точка в координатах: (3, 4)

Особенности:

Требуется определить __match_args__ для позиционного сопоставления

Можно использовать именованные параметры:

case Point(x=x, y=y):

Поддерживает вложенные шаблоны:

case Rectangle(Point(x1, y1), Point(x2, y2)):

Охранные условия (guards):

Добавляют дополнительные условия к шаблонам

def handle_with_guard(value):
    match value:
        case [x, y] if x == y:
            print("Два одинаковых элемента")
        case [x, y] if x > y:
            print(f"Первый элемент больше: {x} > {y}")
        case [x, y]:
            print(f"Два элемента: {x} и {y}")
        case _:
            print("Другая структура")

handle_with_guard([3, 3])  # Два одинаковых элемента
handle_with_guard([5, 2])  # Первый элемент больше: 5 > 2
handle_with_guard([1, 2])  # Два элемента: 1 и 2

Особенности:

Условие if проверяется только если шаблон совпал

Может использовать переменные, связанные в шаблоне

Шаблон OR:

case 1 | 2 | 3:
    print("Число 1, 2 или 3")

Особенности

_ - специальный шаблон, который совпадает с любым значением и не связывает переменную (аналог default в switch других языков).

Порядок имеет значение - интерпретатор проверяет шаблоны сверху вниз и выполняет первый подходящий.

Связывание переменных - если шаблон совпадает, переменные в шаблоне получают соответствующие значения.

Исчерпывающий контроль - можно проверить, что все возможные случаи обработаны (с помощью _ или других шаблонов).

Примеры

Обработка разных типов данных

def handle_value(value):
    match value:
        case int() | float():
            print("Это число")
        case str():
            print("Это строка")
        case list():
            print("Это список")
        case _:
            print("Неизвестный тип")

Обработка команд

Полноценный пример обработки команд с разбором аргументов:

def process_command(command):
    match command.split():
        case ["quit"]:
            print("Завершение работы")
            return False
        case ["load", filename]:
            print(f"Загрузка файла: {filename}")
            # load_file(filename)
        case ["save", filename] | ["write", filename]:
            print(f"Сохранение в файл: {filename}")
            # save_to_file(filename)
        case ["delete", *filenames] if len(filenames) > 0:
            print(f"Удаление файлов: {', '.join(filenames)}")
            # delete_files(*filenames)
        case ["search", query, *options] if "--strict" in options:
            print(f"Строгий поиск: {query}")
            # search(query, strict=True)
        case ["search", query]:
            print(f"Обычный поиск: {query}")
            # search(query)
        case ["help" | "--help" | "-h"]:
            print_help()
        case [cmd, *_]:
            print(f"Неизвестная команда: {cmd}")
        case _:
            print("Пустая команда")
    return True

# Примеры использования:
process_command("load data.txt")     # Загрузка файла: data.txt
process_command("delete a.txt b.txt") # Удаление файлов: a.txt, b.txt
process_command("search python --strict") # Строгий поиск: python
process_command("help")              # Выведет справку

Особенности обработки команд:

Разбиваем команду на части с помощью split()

Используем OR-шаблоны (|) для альтернативных вариантов команд

Применяем охранные условия для дополнительной проверки

*_ захватывает (но игнорирует) оставшиеся аргументы

Можно легко расширять новые команды и варианты синтаксиса

Конструкция match-case делает обработку сложных структур данных и команд более читаемой и поддерживаемой по сравнению с цепочками if-elif-else.

Практика: Задачи на тему Match-Case и их решения по этой ссылке