Conținut curs
Gestionarea erorilor și excepțiilor
0/1
Python Intermediar
Despre lecție

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:

  1. Definim o funcție care primește o funcție ca argument.
  2. În interiorul funcției, definim o altă funcție care va înlocui funcția inițială.
  3. În interiorul funcției înlocuitoare, putem adăuga comportamentul dorit înainte și/sau după apelul funcției inițiale.
  4. Funcția înlocuitoare primește aceleași argumente și returnează același tip de rezultat ca funcția inițială.
  5. Funcția exterioară întoarce funcția înlocuitoare ca rezultat.
python
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.

python
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.

python
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ă.

python
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ă.