Начиная с 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 и их решения по этой ссылке