MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Clase în pattern matching

Python permite utilizarea obiectelor de clasă în pattern matching ca șabloane. Să examinăm un exemplu:

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"Nume: {name}")
       case Person(name="Tom", age=age):
           print(f"Vârstă: {age}")
       case Person(name=name, age=age):
           print(f"Nume: {name}  Vârstă: {age}")


print_person(Person("Tom", 37))  # Default person
print_person(Person("Tom", 22))  # Vârstă: 22
print_person(Person("Sam", 37))  # Nume: Sam
print_person(Person("Bob", 41))  # Nume: Bob  Vârstă: 41

Aici este definită clasa Person, care, prin constructor, primește valori pentru atributele self.name și self.age.

Funcția print_person primește parametrul Person, care, așa cum se presupune, reprezintă un obiect al clasei Person. În interiorul funcției, construcția match compară valoarea parametrului person cu o serie de șabloane. Fiecare șablon reprezintă o definiție a clasei Person, în care fiecărui atribut i se asociază o anumită valoare. De exemplu, primul șablon stabilește strict valorile ambelor atribute:

case Person(name="Tom", age=37):
   print("Default Person")

Acest șablon corespunde obiectului Person dacă atributul name al acestuia are valoarea "Tom", iar atributul age are valoarea 37.

Este important de menționat că acest șablon nu este un apel al constructorului Person. Șablonul doar stabilește cum se asociază atributele cu valorile.

Al doilea șablon stabilește strict valoarea doar pentru atributul age:

case Person(name=name, age=37):
   print(f"Nume: {name}")

Pentru ca acest șablon să se potrivească, atributul age trebuie să fie egal cu 37, iar atributul name poate avea orice valoare. Această valoare este transmisă variabilei name. În acest caz, atât atributul, cât și variabila au aceeași valoare, dar acest lucru nu este obligatoriu, și pentru variabilă se putea folosi un alt nume, de exemplu:

case Person(name=person_name, age=37):      # variabilei person_name i se transmite valoarea atributului name
   print(f"Nume: {person_name}")

Al treilea șablon corespunde unui obiect Person al cărui atribut name este egal cu șirul "Tom", iar valoarea atributului age este transmisă variabilei age:

case Person(name="Tom", age=age):
   print(f"Vârstă: {age}")

În ultimul șablon, atributele name și age pot avea orice valori, iar aceste valori sunt transmise variabilelor cu același nume:

case Person(name=name, age=age):
   print(f"Nume: {name}  Vârstă: {age}")

Nu este necesar să folosim toate atributele obiectului Person. De asemenea, putem folosi pattern-ul _ dacă trebuie să gestionăm cazuri care nu corespund niciunui șablon:

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):         # obținem doar atributul name
           print(f"Nume: {person_name}")
       case _:
           print("Nu este un Person")


print_person(Person("Tom", 37))  # Default person
print_person(Person("Sam", 37))  # Nume: Sam
print_person("Tom")              # Nu este un Person

În acest caz, al doilea șablon Person(name=person_name) corespunde oricărui obiect Person, iar valoarea atributului name este transmisă variabilei person_name.

Ultimul șablon gestionează cazurile în care este transmisă o valoare care nu reprezintă un obiect Person.

Transmiterea unui set de valori

De asemenea, cu ajutorul simbolului vertical | poți defini un set de valori pe care trebuie să le aibă un atribut:

def print_person(person):
   match person:
       case Person(name="Tom" | "Tomas" | "Tommy"):
           print("Default Person")
       case Person(name=person_name):         # obținem doar atributul name
           print(f"Nume: {person_name}")
       case _:
           print("Nu este un Person")


print_person(Person("Tom", 37))     # Default person
print_person(Person("Tomas", 37))   # Default person

În acest caz, primul șablon corespunde unui obiect Person al cărui atribut name are una dintre cele trei valori: "Tom", "Tomas" sau "Tommy".

De asemenea, poți defini valori alternative pentru întregul șablon, inclusiv folosind obiecte din alte clase:

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):    # obținem doar atributul name
           print(f"Nume: {name}")
       case _:
           print("Nu este un Person sau Student")


print_person(Person("Tom", 37))     # Default Person/Student
print_person(Student("Tomas"))      # Default Person/Student


print_person(Person("Bob", 41))     # Nume: Bob
print_person(Student("Mike"))       # Nume: Mike

print_person("Tom")                 # Nu este un Person sau Student

Aici primul șablon:

case Person(name="Tom") | Student(name="Tomas")

corespunde oricărui obiect Person al cărui atribut name este "Tom" și oricărui obiect Student al cărui atribut name este "Tomas".

Al doilea șablon - case Person(name=name) | Student(name=name) corespunde oricărui obiect Person și Student.

Parametrii poziționali

În exemplele de mai sus, pentru a specifica atributele, s-a folosit numele lor: case Person(name="Tom", age=37). Însă, dacă se utilizează mai multe șabloane și în fiecare este necesar să se asocieze atributele obiectului cu anumite valori sau variabile, menționarea constantă a atributelor poate îngreuna codul. Python permite, de asemenea, utilizarea parametrilor poziționali:

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"Nume: {person_name}")
       case Person("Tom", person_age):
           print(f"Vârstă: {person_age}")
       case Person(person_name, person_age):
           print(f"Nume: {person_name}  Vârstă: {person_age}")


print_person(Person("Tom", 37))  # Default person
print_person(Person("Tom", 22))  # Vârstă: 22
print_person(Person("Sam", 37))  # Nume: Sam
print_person(Person("Bob", 41))  # Nume: Bob  Vârstă: 41

Observați în clasa Person apelul funcției:

__match_args__ = ("name", "age")

Datorită acestui fapt, Python va ști că atunci când se specifică atributele, atributul name va fi primul, iar atributul age va fi al doilea.

Astfel, în șabloane nu este necesar să se specifice numele atributului: case Person("Tom", 37) - Python va asocia atributele și valorile/variabilele pe baza poziției lor.

← Lecția anterioară Lecția următoare →