← Контекстные менеджеры · 🏠 Домой · Исключения →
Коротко. python 3.10+. Это не выбор по значению, а сопоставление со
структурой: match умеет разбирать последовательности, словари и объекты,
попутно связывая их части с именами.
# python 3.10+
def handle(command):
match command.split():
case ["go", direction] if direction in ("north", "south"):
return f"идём на {direction}" # guard-условие
case ["look"]:
return "осматриваемся"
case [action, *rest]:
return f"{action} с аргументами {rest}"
case _:
return "неизвестная команда"
handle("go north") # 'идём на north'
handle("take sword") # 'take с аргументами ['sword']'Глубже. Первый подходящий case выигрывает, дальнейшие не проверяются.
case _ — не «default» как ключевое слово, а wildcard-паттерн, который
совпадает с чем угодно и ничего не связывает.
Коротко. Голое имя в case — это захват (capture), а не сравнение.
Оно совпадает с любым значением и присваивает его переменной, затирая ту, что
была снаружи.
RED = "red"
def h(colour):
match colour:
case RED: # НЕ сравнение с RED!
return f"поймано: {colour}"
h("blue") # 'поймано: blue' — ветка сработала на чужом значенииЧтобы сравнить со значением существующего имени, нужен value-паттерн — имя с точкой:
from enum import Enum
class Colour(Enum):
RED = "red"
match colour:
case Colour.RED: # точка -> сравнение, а не захват
...
case "red": # литерал -> тоже сравнение
...
case x if x == RED: # либо через guard
...Подвох. Иногда Python ловит эту ошибку сам: если после case RED: есть
другие ветки, компилятор откажется собирать модуль с
SyntaxError: name capture 'RED' makes remaining patterns unreachable. Но если
ветка последняя, ошибки не будет — код молча начнёт работать неправильно.
Классы — сопоставление по типу и атрибутам:
match point:
case Point(x=0, y=0):
return "начало координат"
case Point(x=0, y=y): # y здесь захватывается
return f"на оси Y, y={y}"
case Point():
return "просто точка"Если у класса задан __match_args__ (у датаклассов он создаётся сам), можно
писать позиционно: case Point(0, y).
Словари — совпадение по подмножеству ключей:
match payload:
case {"type": "user", "id": int(uid)}: # заодно проверка типа
return uid
case {"type": "error", **rest}: # rest — остальные ключи
return restВажно: словарный паттерн совпадает, если перечисленные ключи есть; лишние ключи в объекте совпадению не мешают. Это отличается от паттерна последовательности, где длина должна совпадать точно.
Или-паттерны и захват целого:
match code:
case 200 | 201 | 204:
return "успех"
case 400 | 404 as bad: # as связывает то, что совпало
return f"ошибка клиента: {bad}"Подвох. Строка — это последовательность, но match намеренно её так не
разбирает: case [first, *rest] не сработает на "abc". То же и для bytes.