Tuplas no Pattern Matching - Python
Em Python, tuplas podem ser usadas como padrões no pattern matching. Por exemplo:
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")) # não corresponde a nenhum dos padrões
Nesse caso, a função recebe o parâmetro user
match
user
case ("Tom", 37):
print("default user")
Ou seja, se o primeiro elemento da tupla for "Tom"
37
"default user"
O segundo padrão corresponde a qualquer tupla de dois elementos cujo primeiro elemento seja a string "Tom"
case ("Tom", age):
print(f"Age: {age}")
Aqui, o segundo elemento é atribuído à variável age
"Tom"
37
age
O terceiro padrão é semelhante, mas agora o segundo elemento da tupla deve ser exatamente 22
name
case (name, 22):
print(f"Name: {name}")
Se a tupla de dois elementos não corresponder aos três primeiros padrões, ela corresponderá ao quarto padrão, no qual não nos importamos com os valores específicos: eles são atribuídos às variáveis name
age
case (name, age):
print(f"Name: {name} Age: {age}")
Valores Alternativos
Se for necessário que um elemento da tupla corresponda a um conjunto de valores, esses valores podem ser listados usando o operador |
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
Nesse caso, o primeiro padrão corresponde a uma tupla de dois elementos onde o primeiro elemento é "Tom"
"Tomas"
"Tommy"
Também é possível definir valores alternativos para tuplas inteiras:
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
Aqui, o primeiro padrão corresponderá a duas tuplas específicas: ("Tom", 37)
("Sam", 22)
Omissão de Elementos
Se não nos importamos com um elemento específico da tupla, podemos usar o caractere _
def print_data(user):
match user:
case ("Tom", 37):
print("default user")
case (name, _): # o segundo elemento não é importante
print(f"Name: {name}")
print_data(("Tom", 37)) # default user
print_data(("Sam", 25)) # Name: Sam
print_data(("Bob", 41)) # Name: Bob
Podemos usar o sublinhado para todos os elementos da tupla; nesse caso, os valores desses elementos não são importantes:
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(([1, 2, 3], 41)) # Undefined user
Note que, no último caso, o padrão (_, _)
No exemplo anterior, os padrões aplicados correspondiam apenas a tuplas de dois elementos. No entanto, também é possível usar padrões de tuplas com diferentes números de elementos:
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
Tupla com Número Indefinido de Elementos
Se for necessário comparar uma expressão com uma tupla de comprimento indefinido, podemos usar o símbolo *
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']
No exemplo acima, o parâmetro *rest
("Tom", 37, *rest)
(name, age, *rest)
rest
Se não nos importamos com os elementos restantes, mas ainda queremos corresponder a tuplas com um número indefinido de elementos, podemos usar *_
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)
Nesse caso, *_