Conținut curs
Python Avansat
Despre lecție
  1. Introducere în decoratorii cu parametri

    • Ce sunt decoratorii cu parametri și de ce sunt utili
    • Exemple de decoratori cu parametri în Python
    • Diferența dintre decoratorii fără parametri și decoratorii cu parametri
  2. Crearea unui decorator simplu cu parametri

    • Cum să creați un decorator cu parametri
    • Exemplu: decorator pentru repetarea apelului unei funcții de un număr specificat de ori
    • Exercițiu: creați un decorator cu parametri pentru a limita numărul de apeluri ale unei funcții
  3. Crearea unui decorator cu parametri și valori implicite

    • Cum să creați un decorator cu parametri și valori implicite
    • Exemplu: decorator pentru a adăuga un prefix și/sau un sufix la rezultatul unei funcții
    • Exercițiu: creați un decorator cu parametri și valori implicite pentru a modifica comportamentul unei funcții în funcție de un nivel de logare
  4. Crearea unui decorator cu parametri de tip variabil

    • Cum să creați un decorator cu parametri de tip variabil (args și kwargs)
    • Exemplu: decorator pentru a valida tipurile de date ale argumentelor unei funcții
    • Exercițiu: creați un decorator cu parametri de tip variabil pentru a aplica o serie de transformări asupra rezultatului unei funcții
  5. Utilizarea decoratorilor cu parametri în combinație cu decoratorii fără parametri

    • Cum să combinați decoratorii cu parametri și decoratorii fără parametri
    • Exemplu: combinarea unui decorator de logare cu un decorator de limitare a apelurilor
    • Exercițiu: creați o combinație de decoratori pentru a adăuga funcționalități de verificare a tipurilor de date și de memorare a rezultatelor unei funcții
  6. Folosirea decoratorilor cu parametri pentru metode și clase

    • Cum să utilizați decoratorii cu parametri pentru metode și clase
    • Exemplu: decorator cu parametri pentru a limita numărul de apeluri ale unei metode
    • Exercițiu: creați un decorator cu parametri pentru a adăuga metode suplimentare unei clase, în funcție de parametrii specificați

Exemple și exerciții pentru fiecare subpunct:

Exemplu: decorator pentru repetarea apelului unei funcții de un număr specificat de ori

python
def repetare(numar_repetari):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(numar_repetari):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repetare(3)
def salutare(nume):
    print(f"Salut, {nume}!")

salutare("Andrei")
# Output:
# Salut, Andrei!
# Salut, Andrei!
# Salut, Andrei!

Exercițiu:

Creați un decorator cu parametri pentru a limita numărul de apeluri ale unei funcții. Decoratorul ar trebui să primească un parametru limita și să ridice o excepție atunci când numărul de apeluri ale funcției decorate depășește limita specificată.

Exemplu: decorator pentru a adăuga un prefix și/sau un sufix la rezultatul unei funcții

python
def prefix_suffix(prefix=None, sufix=None):
    def decorator(func):
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            if prefix:
                result = f"{prefix}{result}"
            if sufix:
                result = f"{result}{sufix}"
            return result
        return wrapper
    return decorator

@prefix_suffix(prefix=">>> ", sufix=" <<<")
def mesaj(text):
    return text

print(mesaj("Acesta este un mesaj."))
# Output: >>> Acesta este un mesaj. <<<

Exercițiu:

Creați undecorator cu parametri și valori implicite pentru a modifica comportamentul unei funcții în funcție de un nivel de logare. Decoratorul ar trebui să primească un parametru nivel_logare și să afișeze un mesaj diferit în funcție de acesta.

Exemplu: decorator pentru a valida tipurile de date ale argumentelor unei funcții

python
def validare_tipuri(*tipuri_arg, **tipuri_kwarg):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if len(args) != len(tipuri_arg):
                raise ValueError("Numărul de argumente nu corespunde cu numărul de tipuri specificate.")
            for index, (arg, tip) in enumerate(zip(args, tipuri_arg)):
                if not isinstance(arg, tip):
                    raise TypeError(f"Argumentul {index} trebuie să fie de tipul {tip.__name__}, dar a primit {type(arg).__name__}.")

            for cheie, tip in tipuri_kwarg.items():
                if cheie not in kwargs or not isinstance(kwargs[cheie], tip):
                    raise TypeError(f"Argumentul '{cheie}' trebuie să fie de tipul {tip.__name__}, dar a primit {type(kwargs.get(cheie)).__name__}.")

            return func(*args, **kwargs)
        return wrapper
    return decorator

@validare_tipuri(int, str)
def suma_si_text(numar, text):
    return str(numar) + " " + text

print(suma_si_text(5, "mere"))  # Output: 5 mere
print(suma_si_text("cinci", "mere"))  # Ridică TypeError

Exercițiu:

Creați un decorator cu parametri de tip variabil pentru a aplica o serie de transformări asupra rezultatului unei funcții. Decoratorul ar trebui să primească o listă de funcții de transformare și să aplice fiecare dintre ele în ordine asupra rezultatului funcției decorate.

Exemplu: combinarea unui decorator de logare cu un decorator de limitare a apelurilor

python
def logare(nivel_logare):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if nivel_logare >= 1:
                print(f"Apelând funcția {func.__name__}...")
            result = func(*args, **kwargs)
            if nivel_logare >= 2:
                print(f"Funcția {func.__name__} a fost apelată cu succes.")
            return result
        return wrapper
    return decorator

@logare(1)
@repetare(3)
def salutare(nume):
    print(f"Salut, {nume}!")

salutare("Andrei")
# Output:
# Apelând funcția salutare...
# Salut, Andrei!
# Salut, Andrei!
# Salut, Andrei!

Exercițiu:

Creați o combinație de decoratori pentru a adăuga funcționalități de verificare a tipurilor de date și de memorare a rezultatelor unei funcții. Utilizați decoratorul pentru validarea tipurilor de date dezvoltat anterior și creați un nou decorator pentru memorarea rezultatelor.

Exemplu: decorator cu parametri pentru a limita numărul de apeluri ale unei metode

python
class Contor:
    def __init__(self, limita):
        self.limita = limita
        self.contor = 0

    @repetare(2)
    def incrementare(self):
        if self.contor >= self.limita:
            raise ValueError("Limita de incrementare a fost atinsă.")
        self.contor += 1
        print(f"Contor: {self.contor}")

contor = Contor(3)
contor.incrementare()  # Output: Contor: 1
contor.incrementare()  # Output: Contor: 2
contor.incrementare()  # Ridică ValueError

Exercițiu:

Creați un decorator cu parametri pentru a adăuga metode suplimentare unei clase, în funcție de parametrii specificați. Decoratorul ar trebui să primească un dicționar de metode și să le adauge la clasa decorată.