Un ghid pentru decoratorii Python pentru programatori avansați

Decoratorii Python sunt un instrument puternic și flexibil pentru modificarea comportamentului funcțiilor sau metodelor. Acestea permit programatorilor să extindă sau să modifice funcționalitatea obiectelor apelabile într-un mod curat, ușor de citit și de întreținut. Acest articol explorează concepte avansate legate de decoratorii Python, inclusiv decoratorii imbricați, argumentele decoratorilor și decoratorii bazați pe clasă.

Ce sunt Decoratorii?

Decoratorii sunt funcții care modifică comportamentul unei alte funcții. Ei înglobează o altă funcție pentru a-și extinde comportamentul fără a-i modifica în mod explicit codul. Decoratorii sunt definiți folosind sintaxa @decorator_name și sunt plasați deasupra definiției funcției.

Sintaxa de bază a decoratorului

Un decorator simplu ia o funcție ca argument, definește o funcție interioară care adaugă un anumit comportament și apoi returnează funcția interioară.

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

Decoratorul funcționează cu argumente

Decoratorii pot fi mai flexibili acceptând argumente. Pentru a crea un astfel de decorator, trebuie să scrieți o funcție care returnează un decorator. Acest lucru permite adăugarea unui comportament mai dinamic decoratorilor.

def repeat(num_times):
    def decorator_repeat(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator_repeat

@repeat(num_times=3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Decoratori de cuiburi

Decoratorii pot fi imbricați pentru a combina mai multe comportamente. De exemplu, putem folosi doi sau mai mulți decoratori pe o singură funcție.

def uppercase_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

def repeat_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result + result
    return wrapper

@repeat_decorator
@uppercase_decorator
def say_word(word):
    return word

print(say_word("hello"))

Decoratori de clasă

În Python, decoratorii pot fi implementați și ca clase folosind metoda __call__. Decoratorii bazați pe clasă sunt utili atunci când aveți nevoie de un management și un comportament mai complex de stat.

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print(f"Call {self.num_calls} of {self.func.__name__!r}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()
say_hello()

Folosind functools.wraps pentru a păstra metadatele

Când scrieți decoratori, funcția decorată își pierde metadatele originale, cum ar fi numele și docstring. Decoratorul functools.wraps poate fi folosit pentru a copia metadatele funcției originale în funcția wrapper.

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Wrapper function executed before", func.__name__)
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def display_info(name, age):
    """Displays name and age."""
    print(f"display_info ran with arguments ({name}, {age})")

print(display_info.__name__)  # Output: display_info
print(display_info.__doc__)   # Output: Displays name and age.

Concluzie

Decoratorii Python sunt o caracteristică puternică care permite proiectarea flexibilă a codului și modificarea comportamentului. Utilizarea avansată, cum ar fi decoratorii imbricați, decoratorii cu argumente și decoratorii bazați pe clasă, pot oferi și mai multă funcționalitate și lizibilitate programelor Python. Înțelegând și utilizând corect decoratorii, dezvoltatorii pot scrie cod mai concis, mai eficient și mai ușor de citit.