Classes no Pattern Matching - Python
O Python permite usar objetos de classes como padrões em pattern matching. Vamos considerar um exemplo:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_person(person):
match person:
case Person(name="Tom", age=37):
print("Default Person")
case Person(name=name, age=37):
print(f"Name: {name}")
case Person(name="Tom", age=age):
print(f"Age: {age}")
case Person(name=name, age=age):
print(f"Name: {name} Age: {age}")
print_person(Person("Tom", 37)) # Default Person
print_person(Person("Tom", 22)) # Age: 22
print_person(Person("Sam", 37)) # Name: Sam
print_person(Person("Bob", 41)) # Name: Bob Age: 41
Aqui, definimos a classe Person, que através do construtor recebe valores para os atributos self.name
self.age
A função print_person
person
Person
match
person
case Person(name="Tom", age=37):
print("Default Person")
Este padrão corresponde a um objeto Person
"Tom"
age
37
É importante notar que este padrão não é uma chamada ao construtor Person. O padrão simplesmente estabelece como os atributos são correspondidos a valores.
O segundo padrão define estritamente o valor apenas para o atributo age
case Person(name=name, age=37):
print(f"Name: {name}")
Para corresponder a este padrão, o atributo age
37
name
name
name=name
atributo_do_objeto=variável
print(f"Name: {name}")
name
name
Neste caso, tanto o atributo quanto a variável têm o mesmo nome, mas isso não é obrigatório, e poderíamos ter usado outro nome para a variável. Por exemplo:
case Person(name=person_name, age=37): # O valor do atributo 'name' é atribuído à variável 'person_name'
print(f"Name: {person_name}")
O terceiro padrão corresponde a um objeto Person
name
"Tom"
age
age
case Person(name="Tom", age=age):
print(f"Age: {age}")
No último padrão, os atributos name
age
case Person(name=name, age=age):
print(f"Name: {name} Age: {age}")
Não é obrigatório utilizar todos os atributos do objeto Person
_
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_person(person):
match person:
case Person(name="Tom"):
print("Default Person")
case Person(name=person_name): # Obtém apenas o atributo 'name'
print(f"Name: {person_name}")
case _:
print("Not a Person")
print_person(Person("Tom", 37)) # Default Person
print_person(Person("Sam", 37)) # Name: Sam
print_person("Tom") # Not a Person
Neste caso, o segundo padrão Person(name=person_name)
Person
name
person_name
O último padrão trata casos em que é passado um valor que não representa um objeto Person
Uso de Múltiplos Valores
Podemos também definir um conjunto de valores que um atributo pode ter usando o operador |
def print_person(person):
match person:
case Person(name="Tom" | "Tomas" | "Tommy"):
print("Default Person")
case Person(name=person_name): # Obtém apenas o atributo 'name'
print(f"Name: {person_name}")
case _:
print("Not a Person")
print_person(Person("Tom", 37)) # Default Person
print_person(Person("Tomas", 37)) # Default Person
Neste caso, o primeiro padrão corresponde a um objeto Person
name
"Tom"
"Tomas"
"Tommy"
Também podemos definir valores alternativos para todo o padrão, incluindo objetos de outras classes:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class Student:
def __init__(self, name):
self.name = name
def print_person(person):
match person:
case Person(name="Tom") | Student(name="Tomas"):
print("Default Person/Student")
case Person(name=name) | Student(name=name): # Obtém apenas o atributo 'name'
print(f"Name: {name}")
case _:
print("Not a Person or Student")
print_person(Person("Tom", 37)) # Default Person/Student
print_person(Student("Tomas")) # Default Person/Student
print_person(Person("Bob", 41)) # Name: Bob
print_person(Student("Mike")) # Name: Mike
print_person("Tom") # Not a Person or Student
Aqui, o primeiro padrão case Person(name="Tom") | Student(name="Tomas")
Person
name
"Tom"
Student
name
"Tomas"
O segundo padrão case Person(name=name) | Student(name=name)
Person
Student
name
name
Parâmetros Posicionais
Nos exemplos anteriores, os atributos foram especificados pelo nome, como em case Person(name="Tom", age=37)
class Person:
__match_args__ = ("name", "age")
def __init__(self, name, age):
self.name = name
self.age = age
def print_person(person):
match person:
case Person("Tom", 37):
print("Default Person")
case Person(person_name, 37):
print(f"Name: {person_name}")
case Person("Tom", person_age):
print(f"Age: {person_age}")
case Person(person_name, person_age):
print(f"Name: {person_name} Age: {person_name}")
print_person(Person("Tom", 37)) # Default Person
print_person(Person("Tom", 22)) # Age: 22
print_person(Person("Sam", 37)) # Name: Sam
print_person(Person("Bob", 41)) # Name: Bob Age: 41
Note no código da classe Person a definição:
__match_args__ = ("name", "age")
Isso informa ao Python que, ao especificar os atributos, o atributo name
age
case Person("Tom", 37)