Decorateurs zijn functies die een andere functie accepteren en een nieuwe functie met uitgebreid of gewijzigd gedrag retourneren. Ze worden vaak gebruikt voor logging, autorisatie, caching, uitvoeringstijd en meer.
Decorateurs worden geïmplementeerd met behulp van closures of klassen die de __call__-methode implementeren. De klassieke syntaxis:
# Eenvoudige decorateur def simple_decorator(func): def wrapper(*args, **kwargs): print("Voor het aanroepen van de functie") result = func(*args, **kwargs) print("Na het aanroepen van de functie") return result return wrapper @simple_decorator def my_func(): print("Hoofdfunctie") my_func()
Dit zal als volgt worden uitgevoerd:
Voor het aanroepen van de functie
Hoofdfunctie
Na het aanroepen van de functie
Het belangrijkste voordeel is de encapsulatie van herhalende logica buiten de hoofd business-logica.
Nuances:
functools.wraps gaat de naam van de oorspronkelijke functie en haar docstring verloren.Vraag: "Als ik een functie decoreer met een decorateur en vervolgens probeer de naam van de functie op te vragen via __name__, wat zal ik zien en hoe kan ik de originele naam behouden?"
Antwoord:
Standaard verandert de naam in de naam van de wrapper (meestal wrapper). Om de originele metadata te behouden, gebruik functools.wraps:
import functools def dec(f): @functools.wraps(f) def wrapper(*args): return f(*args) return wrapper @dec def foo(): pass print(foo.__name__) # zal 'foo' afdrukken, en niet 'wrapper'
Verhaal
Bij een grote resource-automatisering was het testsysteem dat gebruik maakte van reflectie op de namen van testfuncties, gebroken na het omhullen van functies met decorateurs. Het probleem was de afwezigheid van functools.wraps.
Verhaal
Een decorateur die logging toevoegde, ondersteunde geen functies met verschillende handtekeningen, omdat *args, **kwargs niet werden gebruikt. Sommige functies faalden stilletjes.
Verhaal
In een project met autorisatie in de REST API implementeerde een ontwikkelaar een decorateur met parameters, maar vergat de functies correct te nesten (er was een tweelaagse nesting in plaats van drie). Hierdoor kon de decorateur geen parameters accepteren.