Кортежи в pattern matching

Последнее обновление: 01.02.2022

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

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850