--- Pattern matching
С релизом python 3.10 появился
Так что же это такое? Начну с самого простого примера, раньше для сравнения с разными элементами использовалась конструкция вида
Теперь мы можем написать это используя
Несколько важных моментов:
Если посмотреть на этот пример, может показаться, что это обычный
И так, во первых,
Важный момент - сравнение с шаблоном считается успешным, только если количество элементов у входящего объекта и количество переменных для распаковки одинаковое
Во вторых, можно распаковывать и сравнивать map объекты, например словари:
И так, я уже рассказал про сравнение списков и словарей, теперь немного о проверке типа входящих данных
--- Дополнительные условия
Чтобы задать дополнительные условия, можно использовать
Указанные в if условия будут проверяться только если совпадает шаблон, по этому можно не опасаться, что передав например в
--- Несколько лайфхаков
Комбинируйте все выше перечисленное и будет вам счастье!)
Уроки по pattern matching:
Документация:
www.python.org
docs.python.org
С релизом python 3.10 появился
pattern matching
, собственно и являющийся главной особенностью этого релиза. Возможно кто-то уже встречал его упрощенную версию - switch-case
- в других языках программирование, но pattern matching
это другое, это намного круче.Так что же это такое? Начну с самого простого примера, раньше для сравнения с разными элементами использовалась конструкция вида
if-else
:
Python:
a = input('Ввидите имя пользователя: ')
if a == 'danila':
print('Привет, Админ!')
elif a == 'anna':
print('Привет, Анна!')
else:
print('Пользователь не найден')
Теперь мы можем написать это используя
pattern matching
:
Python:
a = input('Введите имя пользователя: ')
match a: # Указываем что сравнивать
case 'danila': # Если a == 'danila'
print('Привет, Админ!')
case 'anna': # Если a == 'anna'
print('Привет, Анна!')
case _: # Во всех остальных случаях
print('Пользователь не найден')
Несколько важных моментов:
_
- По умолчанию равен чему угодно, любым данным, по этомуcase _
это то же самое, что иelse
- В отличии от некоторых других яп, в python реализации после успешного выполнения
case
консрукция сразу завершается, не сравнивая входящие данные с шаблонами в другихcase
Если посмотреть на этот пример, может показаться, что это обычный
switch-case
, не более, но это просто пример для базового понимания работы конструкции, перейдем к более интересным примерам.И так, во первых,
pattern matching
поддерживает распаковку list и tupe (если передать переменные просто через ,
то это тоже будет считаться как кортеж):
Python:
mas = [1, 2, 3, 4, 5]
match mas:
# Если имеет РОВНО 4 элемента, то он распакуется в указанные переменные
# Можно обернуть в [], тут, можно в (), а можно вообще не оборачивать, как дальше
case [b, c, d, e]:
print(b)
# При любом количестве элементов распакует первый элемент в b
# А остальные в виде списка в c
case b, *c:
print(c) # [2, 3, 4, 5]
# Немного непривычно, но сборщик элементов может находиться на любой позиции
case b, *c, d:
print(*c) # [2, 3, 4]
# А можно вообще не писать сборщик
case b, c, :
print(b, c) # 1 2
# Хотите проверить что массив состоит из 3-х элементов, но 1-й и 3-й вам не нужны?
case _, b, _:
print(b)
# А может вы хотите проверить, что 2-й элемент массива это 2?
case _, 2, *_:
print('second elem: 2')
Важный момент - сравнение с шаблоном считается успешным, только если количество элементов у входящего объекта и количество переменных для распаковки одинаковое
Во вторых, можно распаковывать и сравнивать map объекты, например словари:
Python:
men = {
'name': 'danila',
'nickname': 'DaSh-More',
'age': 18,
'moderator': True,
'posts_id': [
11111,
22222,
33333
]
}
match men:
# Если есть ключи name и nickname
# 'danila' распакуется в переменную name
# При чем неважно, сколько ключей в словаре, главное что есть указанные
case {'name': name, 'nickname': _}:
print(name)
# Можно сравнивать более глубокие данные
case {'posts_id': [11111, *n]}:
print(n) # [22222, 33333]
# Можно распаковывать остальные ключи в отдельную переменную
case {'name':_, **data}:
print(data)
Важный момент, в отличии от распаковки списков и кортежей, при сравнении словарей проверяется только наличие указанных ключей, если в словаре ключей больше, но при этом есть нужные (указанные в шаблоне), сравнение все равно пройдет успешно
И так, я уже рассказал про сравнение списков и словарей, теперь немного о проверке типа входящих данных
Python:
mas = [1, 2, 3, 4, 5]
match mas:
# Чтобы проверить тип объекта, надо просто вызвать создание этого объекта
case list():
print(mas)
# Если в скобках указать переменную, объект запишется в нее
case list(b):
print(c)
Важный момент, если вы используете не стандартный тип данных, у вас может не получиться его проверить.
Это не значит что это невозможно, просто работает это немного сложней и тут я это разбирать не буду.
Подробнее тут: https://www.python.org/dev/peps/pep-0636/#adding-a-ui-matching-objects
При проверке класса не создается объект класса
--- Дополнительные условия
Чтобы задать дополнительные условия, можно использовать
if
, который принято называть guard (защита, ограничение)
Python:
mas = [1, 2, 3, 4, 5]
match mas:
# Если передан массив, и при этом его длина > 3
case list(b) if len(b) > 3:
print(b)
mas
число, мы получим ошибку на этапе применения функции len
к числу, до этого этапа дело просто не дойдет--- Несколько лайфхаков
- Если вам надо чтобы несколько шаблонов завершались с одним результатом, иногда можно указать этот результат после всего, а в шаблонах прописать
pass
:
Python:def test(data): match data: case 200: return True case 404: pass case 402: pass case 414: pass case _: return None # При указанных кодах 4.. вернет False return False
- Чтобы сравнить переменную со значением, ее нужно задать явно
Python:bar = 123 test = 77 match bar: # Не сравнит bar и test, а распакует bar в test case test: print(test) # 123 # Чтобы этого избежать, надо использовать либо переменные с точкой case math.pi: # Сравнит bar и pi print(bar) # Либо писать вот так: case b if b == test: print(b)
- Несколько шаблонов можно указать через
|
:
Python:bar = [1, 2, 3] match bar: case (1, num, 0) | (num, 2, 3): print(num) # 1
Важный момент, при таком использовании нескольких шаблонов в которых что-то распаковывается (тут num) переменные в которые что-то распаковывается должны иметь одинаковое название в обоих шаблонах и присутствовать так же в обоих (нельзя в одном шаблоне использовать num, а во втором ее не использовать) - Любую часть можно распаковать в переменную
Python:bar = [1, 2, 3] match bar: # Проверяем что 3-й элемент тоже число, и распаковываем его case (1, (2 | '2'), int() as k) print(k) # 3
Комбинируйте все выше перечисленное и будет вам счастье!)
Уроки по pattern matching:
Документация:

PEP 636 – Structural Pattern Matching: Tutorial | peps.python.org
This PEP is a tutorial for the pattern matching introduced by PEP 634.

8. Compound statements
Compound statements contain (groups of) other statements; they affect or control the execution of those other statements in some way. In general, compound statements span multiple lines, although i...
Последнее редактирование: