Een gids voor Python-decorators voor gevorderde programmeurs

Python-decorators zijn een krachtige en flexibele tool voor het aanpassen van het gedrag van functies of methoden. Ze stellen programmeurs in staat om de functionaliteit van aanroepbare objecten op een schone, leesbare en onderhoudbare manier uit te breiden of te wijzigen. Dit artikel onderzoekt geavanceerde concepten met betrekking tot Python-decorators, waaronder geneste decorators, decoratorargumenten en op klassen gebaseerde decorators.

Wat zijn decorateurs?

Decorators zijn functies die het gedrag van een andere functie wijzigen. Ze omsluiten een andere functie om het gedrag ervan uit te breiden zonder expliciet de code ervan te wijzigen. Decorators worden gedefinieerd met de syntaxis @decorator_name en worden boven de functiedefinitie geplaatst.

Basis Decorator Syntaxis

Een eenvoudige decorator neemt een functie als argument, definieert een interne functie die bepaald gedrag toevoegt en retourneert vervolgens de interne functie.

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()

Decoratorfuncties met argumenten

Decorators kunnen flexibeler zijn door argumenten te accepteren. Om zo'n decorator te maken, moet u een functie schrijven die een decorator retourneert. Dit maakt het mogelijk om dynamischer gedrag aan de decorators toe te voegen.

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")

Nestende decorateurs

Decorators kunnen worden genest om meerdere gedragingen te combineren. We kunnen bijvoorbeeld twee of meer decorators op één functie gebruiken.

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"))

Klasse-gebaseerde decorateurs

In Python kunnen decorators ook worden geïmplementeerd als klassen door de __call__-methode te gebruiken. Op klassen gebaseerde decorators zijn handig wanneer u complexere statusbeheer en gedrag nodig hebt.

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()

Met functools.wraps meten om metagegevens te behouden

Wanneer u decorators schrijft, verliest de gedecoreerde functie zijn originele metadata, zoals de naam en docstring. De decorator functools.wraps kan worden gebruikt om de metadata van de originele functie naar de wrapperfunctie te kopiëren.

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.

Conclusie

Python-decorators zijn een krachtige functie die flexibel codeontwerp en gedragswijziging mogelijk maakt. Geavanceerd gebruik, zoals geneste decorators, decorators met argumenten en op klassen gebaseerde decorators, kunnen nog meer functionaliteit en leesbaarheid bieden aan Python-programma's. Door decorators correct te begrijpen en te gebruiken, kunnen ontwikkelaars bondigere, efficiëntere en leesbare code schrijven.