Obiective:
- Recapitularea conceptului de decorator în Python
- Crearea de decoratori personalizați în funcție de cerințele specifice
- Exemple practice de decoratori personalizați
Recapitulare
Decoratorii sunt o caracteristică puternică și flexibilă a limbajului Python, care permit modificarea sau extinderea comportamentului unei funcții sau metode fără a modifica codul acesteia. Un decorator este o funcție care primește o funcție ca argument și întoarce o altă funcție care încorporează sau extinde comportamentul funcției inițiale.
Crearea de decoratori personalizați
Pentru a crea un decorator personalizat, trebuie să urmăm următorii pași:
- Definim o funcție care primește o funcție ca argument.
- În interiorul funcției, definim o altă funcție care va înlocui funcția inițială.
- În interiorul funcției înlocuitoare, putem adăuga comportamentul dorit înainte și/sau după apelul funcției inițiale.
- Funcția înlocuitoare primește aceleași argumente și returnează același tip de rezultat ca funcția inițială.
- Funcția exterioară întoarce funcția înlocuitoare ca rezultat.
def decorator_personalizat(func):
def func_decorată(*args, **kwargs):
# Comportament înainte de apelul funcției inițiale
rezultat = func(*args, **kwargs)
# Comportament după apelul funcției inițiale
return rezultat
return func_decorată
Exemple practice de decoratori personalizați
1. Decorator pentru logarea apelurilor de funcție
Acest decorator va înregistra într-un fișier de log data, ora și numele funcției apelate.
import datetime
def logare_apeluri(func):
def func_decorată(*args, **kwargs):
timestamp = datetime.datetime.now()
with open("apeluri.log", "a") as log_file:
log_file.write(f"{timestamp}: Apel funcție {func.__name__}n")
return func(*args, **kwargs)
return func_decorată
@logare_apeluri
def salut(nume):
return f"Salut, {nume}!"
print(salut("Andrei"))
2. Decorator pentru validarea argumentelor unei funcții
Acest decorator va valida argumentele unei funcții înainte de a o apela și va arunca o excepție în cazul în care argumentele nu sunt valide.
def validare_argumente(validator):
def decorator(func):
def func_decorată(*args, **kwargs):
if not validator(*args, **kwargs):
raise ValueError("Argumente invalide!")
return func(*args, **kwargs)
return func_decorată
return decorator
def validator_pătrat(a, b):
return isinstance(a, int) and isinstance(b, int)
@validare_argumente(validator_pătrat)
def pătrat(a, b):
return a ** b
print(pătrat(2, 3))
3. Decorator pentru limitarea numărului de apeluri ale unei funcții
Acest decorator va limita numărul de apeluri ale unei funcții și va arunca o excepție în cazul în care limita este depășită.
def limitare_apeluri(limita):
def decorator(func):
apeluri = 0
def func_decorată(*args, **kwargs):
nonlocal apeluri
if apeluri >= limita:
raise RuntimeError("Limita de apeluri a fost depășită!")
apeluri += 1
return func(*args, **kwargs)
return func_decorată
return decorator
@limitare_apeluri(3)
def salut(nume):
return f"Salut, {nume}!"
for i in range(5):
try:
print(salut("Andrei"))
except RuntimeError as e:
print(e)
## Recapitulare și exerciții propuse
În această lecție, am recapitulat conceptul de decorator în Python și am învățat cum să creăm decoratori personalizați în funcție de cerințele specifice. Am văzut, de asemenea, câteva exemple practice de decoratori personalizați.
Exerciții propuse:
1. Creați un decorator `cronometru` care să măsoare și să afișeze timpul de execuție al unei funcții. Folosiți acest decorator pentru a măsura timpul de execuție al unei funcții care calculează al n-lea număr din șirul Fibonacci.
2. Creați un decorator `memoizare` care să stocheze rezultatele apelurilor unei funcții și să le returneze direct fără a recalcula funcția în cazul în care aceeași funcție este apelată cu aceleași argumente. Folosiți acest decorator pentru a optimiza o funcție care calculează al n-lea număr din șirul Fibonacci.
3. Creați un decorator `exceptie_personalizata` care să primească ca argument o excepție și să o arunce în cazul în care funcția decorată întoarce `None`. Aplicați acest decorator unei funcții care caută un element într-o listă și returnează poziția acestuia sau `None` în cazul în care elementul nu se află în listă.