Механизм сопоставления с образцом появился в Python 3.10 под названием Structural Pattern Matching и реализован с помощью конструкции match-case. Этот инструмент позволяет элегантно и лаконично анализировать сложные структуры данных, сопоставляя их с шаблонами.
Во многих функциональных языках (например, в Haskell, Scala) pattern matching давно считается удобным способом ветвления логики по структуре данных. Python долгое время не имел такого механизма, обходясь цепочками if-elif-else или распаковкой.
Сложные вложенные структуры данных (словари, списки, объекты) зачастую требуют множественных проверок на типы, значения и структуру, что приводит к путаному коду со множеством условий.
match-case предоставляет декларативный и читабельный способ описания разных сценариев обработки данных с учетом типа и структуры без нагромождения условий.
def process(event): match event: case {"type": "click", "x": x, "y": y}: return f"Click at ({x}, {y})" case [command, *args]: return f"Command: {command}, args: {args}" case _: return "Unknown event" print(process({"type": "click", "x": 2, "y": 5})) # Click at (2, 5) print(process(["RUN", 1, 2, 3])) # Command: RUN, args: [1, 2, 3]
Сопоставляет ли match-case только по значению? Нет. Сопоставление может происходить по структуре, типу, распаковке коллекций и даже свойств объектов (если указать специальные методы match_args).
Влияет ли порядок case в match? Да. Анализ идет сверху вниз, первый подходящий шаблон срабатывает. Последующие case не проверяются.
Можно ли сопоставлять пользовательские классы? Да, если класс реализует методы match_args и/или getitem. Тогда pattern matching сможет извлекать значения полей.
class Point: __match_args__ = ("x", "y") def __init__(self, x, y): self.x = x self.y = y def where(obj): match obj: case Point(x, y): return f"Point at {x}, {y}" case _: return "Unknown" print(where(Point(1, 2))) # Point at 1, 2
Плюсы:
Негативный кейс: Разработчики использовали match-case даже для простых булевых ветвлений, что только усложнило код. Плюсы: изучили новую фичу. Минусы: потеряли читаемость и увеличили количество ошибок.
Положительный кейс: В приложении с большим числом событий и вложенных структур (например, графовый парсер) match-case позволил избежать громоздких if-elif и централизовать парсинг. Плюсы: выросла читаемость, снизилось количество багов. Минусы: потребовалось обучение команды работе с новой конструкцией.