MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Decoratori

Decoratori în Python reprezintă funcții care primesc ca parametru o altă funcție și returnează, de asemenea, o funcție. Decoratorii permit modificarea unei funcții, a parametrilor săi și a rezultatului său fără a modifica codul sursă al acestei funcții.

Să analizăm un exemplu simplu:

# definirea funcției decorator
def select(input_func):
   def output_func():  # definim funcția care va fi executată în locul celei originale
       print("*****************")  # înainte de a afișa funcția originală, afișăm niște steluțe
       input_func()  # apelăm funcția originală
       print("*****************")  # după ce afișăm funcția originală, afișăm niște steluțe
   return output_func  # returnăm noua funcție

# definirea funcției originale
@select  # aplicarea decoratorului select
def hello():
   print("Hello www.fabricadecoduri.com")

# apelăm funcția originală
hello()

La început, este definită funcția decoratorului, care în acest caz se numește select(). Ca parametru, decoratorul primește o funcție (în acest caz, parametrul input_func), la care acest decorator va fi aplicat:

def select(input_func):
   def output_func():  # definim funcția care va fi executată în locul celei originale
       print("*****************")  # înainte de a afișa funcția originală, afișăm niște steluțe
       input_func()  # apelăm funcția originală
       print("*****************")  # după ce afișăm funcția originală, afișăm niște steluțe
   return output_func  # returnăm noua funcție

Rezultatul decoratorului în acest caz este funcția locală output_func, în care este apelată funcția de intrare input_func. Pentru simplitate, aici, înainte și după apelul lui input_func, afișăm un set de caractere "*".

Apoi este definită funcția standard la care se aplică decoratorul - în acest caz, este funcția hello, care doar afișează pe consolă un mesaj:

@select  # aplicarea decoratorului select
def hello():
   print("Hello www.fabricadecoduri.com")

Pentru a aplica decoratorul, înainte de definirea funcției se folosește simbolul @, urmat de numele decoratorului. Deci, în acest caz, funcției hello() i se aplică decoratorul select().

Apoi apelăm funcția obișnuită:

hello()

Deoarece funcției i se aplică decoratorul select, funcția hello este transmisă în decoratorul select() ca parametru input_func. Și deoarece decoratorul returnează o nouă funcție - output_func, în acest caz, se va executa de fapt funcția output_func().

Rezultatul afișării pe consolă va fi:

*****************
Hello www.fabricadecoduri.com
*****************

Preluarea parametrilor funcției în decorator

Decoratorul poate intercepta argumentele transmise funcției:

# definirea funcției decorator
def check(input_func):
   def output_func(*args):  # prin *args preluăm valorile parametrilor funcției originale
       input_func(*args)  # apelăm funcția originală
   return output_func  # returnăm noua funcție

# definirea funcției originale
@check
def print_person(name, age):
   print(f"Name: {name}  Age: {age}")

# apelăm funcția originală
print_person("Tom", 38)

Aici, funcția print_person() primește doi parametri: name (nume) și age (vârstă). Acestei funcții i se aplică decoratorul check.

În decoratorul check se returnează funcția locală output_func(), care primește un set de valori sub forma parametrului *args - acestea sunt valorile care sunt transmise funcției originale căreia i se aplică decoratorul. Adică, în acest caz, *args va conține valorile parametrilor name și age.

def check(input_func):
   def output_func(*args):  # prin *args preluăm valorile parametrilor funcției input_func
       input_func(*args)

Aici pur și simplu transmitem aceste valori funcției originale:

input_func(*args)

Rezultatul pe consolă va fi:

Name: Tom  Age: 38

Dar ce se întâmplă dacă în funcția print_person va fi transmisă o valoare inacceptabilă, de exemplu, o vârstă negativă? Unul dintre avantajele decoratorilor este că putem verifica și, dacă este necesar, modifica valorile parametrilor. De exemplu:

# definirea funcției decorator
def check(input_func):
   def output_func(*args):
       name = args[0]
       age = args[1]  # preluăm valoarea celui de-al doilea parametru
       if age < 0: age = 1  # dacă vârsta este negativă, o modificăm la 1
       input_func(name, age)  # transmitem funcției valorile parametrilor
   return output_func

# definirea funcției originale
@check
def print_person(name, age):
   print(f"Name: {name}  Age: {age}")

# apelăm funcția originală
print_person("Tom", 38)
print_person("Bob", -5)

args reprezintă un set de valori, și, folosind indicii, putem prelua valorile parametrilor pe poziții și putem face ceva cu ele. Astfel, aici, dacă valoarea vârstei este mai mică de 0, o setăm la 1. Apoi transmitem aceste valori la apelul funcției. Rezultatul pe consolă va fi:

Name: Tom  Age: 38
Name: Bob  Age: 1

Preluarea rezultatului funcției

Similar, putem prelua rezultatul funcției și, dacă este necesar, să-l modificăm:

# definirea funcției decorator
def check(input_func):
   def output_func(*args):
       result = input_func(*args)  # transmitem funcției valorile parametrilor
       if result < 0: result = 0  # dacă rezultatul funcției este mai mic de zero, returnăm 0
       return result
   return output_func

# definirea funcției originale
@check
def sum(a, b):
   return a + b

# apelăm funcția originală
result1 = sum(10, 20)
print(result1)  # 30

result2 = sum(10, -20)
print(result2)  # 0

Aici este definită funcția sum(), care returnează suma numerelor. În decoratorul check, verificăm rezultatul funcției și, pentru simplitate, dacă acesta este mai mic de zero, returnăm 0.

Rezultatul afișării pe consolă va fi:

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