Освойте новую функцию Pattern Matching в Python 3.10. Мы рассмотрим все различные варианты синтаксиса кода.
Сопоставление с образцом, безусловно, самая интересная новая функция в новой версии Python 3.10, и в этом руководстве вы узнаете о ней все!
Его довольно просто понять, но он также содержит множество различных вариантов синтаксиса кода, которые вы можете использовать. Сейчас мы рассмотрим их все. Мы начнем с основного синтаксиса, а затем перейдем ко всем деталям.
1 Basic Syntax
Основной синтаксис довольно прост. Вы используете ключевое слово match и ключевое слово case, а затем можете сопоставлять переменную с разными значениями. Для каждого совпадающего случая вы можете выполнить определенное действие.
В простейшем случае, как здесь, мы сопоставляем простые значения, но вы также можете использовать сложные шаблоны. Вы увидите, что я имею в виду через несколько минут.
Синтаксис:
match subject: case <pattern_1>: <action_1> case <pattern_2>: <action_2> case _: <action_wildcard>
Пример:
def http_error(status): match status: case 400: return "Bad request" case 401 | 403: return "Not allowed" case 404: return "Not found" case 418: return "I'm a teapot" case _: return "Something's wrong with the internet"
2 Multiple Matches
Мы можем сопоставлять несколько значений в одной строке, используя оператор канала
def http_error(status):
match status:
case 400:
return "Bad request"
case 401 | 403 | 404:
return "Not allowed"
3 No Fall Through
По сравнению с другими языками программирования важно отметить, что здесь мы не пропускаем все случаи. Например, значение 400 здесь выводит только Bad request. В других языках, таких как C++, это пропустит все случаи, а также напечатает все другие операторы, если мы не используем оператор break . Но нам это не нужно здесь, в Python.
def http_error(status): match status: case 400: print("Bad request") case 401 | 403 | 404: print("Not allowed")
4 Wildcard
В качестве подстановочного знака используется одно подчеркивание. Это означает, что если ни один из приведенных выше шаблонов не соответствует, выполняется действие подстановочного знака. Это необязательно, поэтому вы также можете его опустить, и тогда вообще ничего не произойдет, если совпадение не будет найдено.
def http_error(status): match status: case 400: return "Bad request" case _: return "Something's wrong with the internet"
5 Unpacking and Variable Binding
Шаблоны могут выглядеть как распаковывающие назначения, и шаблон может использоваться для связывания переменных. В этом примере мы сопоставляем кортеж здесь, и точка данных может быть распакована по ее координатам x и y. Затем мы можем использовать связанную переменную в операторе выполнения.
# point is an (x, y) tuple
match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"Y={y}")
case (x, 0):
print(f"X={x}")
case (x, y):
print(f"X={x}, Y={y}")
case _:
raise ValueError("Not a point")
6 Patterns and Classes
Если вы используете классы для структурирования своих данных, вы можете использовать в качестве шаблона имя класса, за которым следует список аргументов, соответствующих аргументам конструктора. Этот шаблон имеет возможность записывать атрибуты класса в переменные.
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
def location(point):
match point:
case Point(x=0, y=0):
print("Origin is the point's location.")
case Point(x=0, y=y):
print(f"Y={y} and the point is on the y-axis.")
case Point(x=x, y=0):
print(f"X={x} and the point is on the x-axis.")
case Point():
print("The point is located somewhere else on the plane.")
case _:
print("Not a point")
7 Patterns With Positional Parameters
Мы можем использовать позиционные аргументы, если, например, используем встроенный класс данных, обеспечивающий порядок атрибутов. Тогда все эти шаблоны с позиционными аргументами или аргументами ключевого слова эквивалентны.
Point(1, var)
Point(1, y=var)
Point(x=1, y=var)
Point(y=var, x=1)
8 Nested Patterns
Шаблоны могут быть вложены друг в друга. Например, если наши данные представляют собой короткий список точек, их можно сопоставить следующим образом. Здесь мы сопоставляем различные возможные списки.
points = [Point(0, 0), Point(1, 1)] match points: case []: print("No points in the list.") case [Point(0, 0)]: print("The origin is the only point in the list.") case [Point(x, y)]: print(f"A single point {x}, {y} is in the list.") case [Point(0, y1), Point(0, y2)]: print(f"Two points on the Y axis at {y1}, {y2} are in the list.") case _: print("Something else is found in the list.")
9 Complex Patterns and the Wildcard
Подстановочный знак можно использовать не только в качестве последнего оператора case, но и в более сложных шаблонах, таких как кортежи. В этом примере переменная состояния соответствует всем кортежам с ошибкой, кодом, а затем любым произвольным номером состояния.
status = ('error', 'Client Error', 100)
match status:
case ('warning', code, 10):
print("A warning has been received.")
case ('error', code, _):
print(f"An error {code} occurred.")
10 Guard
Мы можем добавить предложение if к шаблону, известному как «защита». И если гвардия ложна, совпадение переходит к следующему блоку case.
match point: case Point(x, y) if x == y: print(f"The point is located on the diagonal Y=X at {x}.") case Point(x, y): print(f"Point is not on the diagonal.")
11 More on Sequences
Шаблоны последовательности также поддерживают подстановочные знаки: эта звездочка в кортеже или списке работает аналогично подстановочным знакам в назначениях распаковки. Таким образом, эти примеры сопоставляют последовательность как минимум из двух элементов, а затем привязывают все оставшиеся элементы к остальным. Имя после звезды также может быть символом подчеркивания, если вам не нужно привязывать остальные элементы.
[x, y, *rest]
(x, y, *rest)
(x, y, *_)
12 Mapping Patterns
Подобно последовательностям, мы также можем сопоставлять сопоставления. В этом примере он захватывает значения «пропускной способности» и «задержки» из словаря. Но здесь, в отличие от шаблонов последовательности, лишние ключи игнорируются. Подстановочный знак с двойными звездочками также поддерживается, но двойные звездочки и подчеркивание были бы излишними, поэтому это не разрешено.
{"bandwidth": b, "latency": l}
{"bandwidth": b, **rest}
# {"bandwidth": b, **_} Not allowed!
13 Match with Enum
Конечно, мы также можем сопоставлять перечисления, используя полное имя:
from enum import Enum class Color(Enum): RED = 0 GREEN = 1 BLUE = 2 match color: case Color.RED: print("I see red!") case Color.GREEN: print("Grass is green") case Color.BLUE: print("I'm feeling the blues :(")
14 Bind Subpatterns with as
И последняя возможность, которую я покажу вам, заключается в том, что подшаблоны могут быть захвачены с помощью ключевого слова as:
В этом примере он связывает x1, y1, x2, y2, как и следовало ожидать без предложения as. И это также связывает p2 со всем вторым элементом.
points = (Point(0, 0), Point(1, 1)) match points: case (Point(x1, y1), Point(x2, y2) as p2): print(p2) # --> Point(x=1, y=1)