В качестве шаблонов в 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)