В качестве шаблонов в pathern matching в Python могут выступать кортежи. Например:
def print_data(user): match user: case ("Tom", 37): print("default user") case ("Tom", age): print(f"Age: {age}") case (name, 22): print(f"Name: {name}") case (name, age): print(f"Name: {name} Age: {age}") print_data(("Tom", 37)) # default user print_data(("Tom", 28)) # Age: 28 print_data(("Sam", 22)) # Name: Sam print_data(("Bob", 41)) # Name: Bob Age: 41 print_data(("Tom", 33, "Google")) # не соответствует ни одному из шаблонов
В данном случае функция принимает параметр user, который, как предполагается, представляет кортеж из двух элементов. И конструкция match сравнивает этот кортеж с рядом шаблонов. Первый шаблон предполагает, что кортеж user точно соответствует набору значений:
case ("Tom", 37): print("default user")
То есть, если первый элемент кортежа равен "Tom", а второй - 37, то на консоль выводится строка "default user"
Второй шаблон соответствует любому двухэлементному кортежу, первый элемент которого равен строке "Tom":
case ("Tom", age): print(f"Age: {age}")
Для второго элемента определяется переменная age. В итоге, если первый элемент кортежа равен строке "Tom", а второй не равен 37, то такой кортеж будет соответствовать второму шаблону. Причем второй элемент будет передаваться переменной age.
Третий шаблон во многом аналогичен, только теперь строго определен второй элемент кортежа - он должен быть равен 22, а первый попадает в переменную name:
case (name, 22): print(f"Name: {name}")
Если двухэлементный кортеж не соответствует первому, второму и третьему шаблонам, то он будет соответствовать четвертому шаблону, в которому нам не важные конкретные значения - для них определены переменные name и age:
case (name, age): print(f"Name: {name} Age: {age}")
Если необходимо, чтобы элемент кортежа соответствовал набору значений, то эти значения можно перечислить через вертикальную черту:
def print_data(user): match user: case ("Tom" | "Tomas" | "Tommy", 37): print("default user") case ("Tom", age): print(f"Age: {age}") case (name, 22): print(f"Name: {name}") case (name, age): print(f"Name: {name} Age: {age}") print_data(("Tom", 37)) # default user print_data(("Tomas", 37)) # default user print_data(("Tom", 28)) # Age: 28 print_data(("Sam", 37)) # Name: Sam Age: 37
В данном случае первый шаблон соответствует двухэлементному кортежу, где первый элемент равен или "Tom", или "Tomas", или "Tommy".
Также можно задать альтернативные значения для отдельных элементов, но и альтернативные кортежи:
def print_data(user): match user: case ("Tom", 37) | ("Sam", 22): print("default user") case (name, age): print(f"Name: {name} Age: {age}") print_data(("Tom", 37)) # default user print_data(("Sam", 22)) # default user print_data(("Mike", 28)) # Name: Mike Age: 28
В данном случае первый шаблон будет соответствовать двум кортежам: ("Tom", 37)
и ("Sam", 22)
Если нам не важен какой-то элемент кортежа, то в шаблоне вместо конкретного значния или переменной можно указать шаблон _:
def print_data(user): match user: case ("Tom", 37): print("default user") case (name, _): # второй элемент не важен print(f"Name: {name}") print_data(("Tom", 37)) # default user print_data(("Sam", 25)) # Name: Sam print_data(("Bob", 41)) # Name: Bob
Можно использовать прочерки для всех элементов кортежа, в этом случае значения всех этих элементов будут не важны:
def print_data(user): match user: case ("Tom", 37): print("default user") case ("Sam", _): print("Name: Sam") case (_, _): print("Undefined user") print_data(("Tom", 37)) # default user print_data(("Sam", 25)) # Name: Sam print_data(("Bob", 41)) # Undefined user
В причем в последнем случае шаблон (_, _)
по прежнему соответствует только двухэлементному кортежу
В примере выше применяемые шаблоны соответствовали только двухэлементному кортежу. Однако также можно использовать одновременно шаблоны кортежей с разным количеством элементов:
def print_data(user): match user: case (name, age): print(f"Name: {name} Age: {age}") case (name, age, company): print(f"Name: {name} Age: {age} Company: {company}") case (name, age, company, lang): print(f"Name: {name} Age: {age} Company: {company} Language: {lang}") print_data(("Tom", 37)) # Name: Tom Age: 37 print_data(("Sam", 22, "Microsoft")) # Name: Sam Age: 22 Company: Microsoft print_data(("Bob", 41, "Google", "english")) # Name: Bob Age: 41 Company: Google Language: english
Если необходимо сравнивать выражение с кортежем неопределенной длины, то можно определять все остальные значения кортежа с помощью символа * (звездочки):
def print_data(user): match user: case ("Tom", 37, *rest): print(f"Rest: {rest}") case (name, age, *rest): print(f"{name} ({age}): {rest}") print_data(("Tom", 37)) # Rest: [] print_data(("Tom", 37, "Google")) # Rest: ["Google"] print_data(("Bob", 41, "Microsoft", "english")) # Bob (41): ["Microsoft", "english"]
В примере выше применяется параметр *rest
, который соответствует всем остальным элементам. То есть в примере выше
шаблоны ("Tom", 37, *rest)
и (name, age, *rest)
соответствуют любому кортежу с двумя элементами и больше. Все элементы начиная с третьего будут помещаться в параметр rest, который представляет
массив значений.
Если нам этот параметр (rest) не важен, но мы по прежнему хотим, чтобы шаблон соответствовал кортежу с неопределенным количеством элементов,
мы можем использовать подшаблон *_
:
def print_data(user): match user: case ("Tom", 37, *_): print("Default user") case (name, age, *_): print(f"{name} ({age})") print_data(("Tom", 37)) # Default user print_data(("Tom", 37, "Google")) # Default user print_data(("Bob", 41, "Microsoft", "english")) # Bob (41)