Hur man använder Python Decorators för att förbättra funktioner

Python-dekoratörer är ett kraftfullt och flexibelt sätt att modifiera eller förbättra funktioner och metoder. Dekoratörer ger ett sätt att omsluta en funktion med ytterligare funktionalitet, så att du kan utöka dess beteende utan att ändra dess faktiska kod. Den här artikeln kommer att introducera dig till konceptet med dekoratörer, hur man skapar och använder dem, och utforska några praktiska exempel.

Vad är en dekoratör?

En dekoratör är en funktion som tar en annan funktion och utökar sitt beteende utan att explicit modifiera det. I Python används dekoratörer ofta för att lägga till funktionalitet som loggning, åtkomstkontroll eller prestandamätning till befintliga funktioner eller metoder. Dekoratorer tillämpas på funktioner med syntaxen @decorator_name.

# Basic example of a decorator
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()

Så fungerar dekoratörer

När du använder en dekoratör på en funktion, utför Python i huvudsak följande steg:

  1. Dekorationsfunktionen anropas med den ursprungliga funktionen som argument.
  2. Dekorationsfunktionen definierar en ny funktion (ofta kallad wrapper) som förbättrar eller modifierar den ursprungliga funktionens beteende.
  3. Dekorationsfunktionen returnerar den nya funktionen.
  4. När den dekorerade funktionen anropas, anropar den faktiskt den nya funktionen som returneras av dekoratören.

Skapa en enkel dekoratör

Låt oss skapa en enkel dekoratör som mäter utförandetiden för en funktion. Detta är användbart för prestandatestning och optimering.

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Execution time: {end_time - start_time} seconds")
        return result
    return wrapper

@timing_decorator
def slow_function():
    time.sleep(2)
    print("Function finished!")

slow_function()

Använda dekoratörer med argument

Ibland kanske du vill skicka argument till din dekoratör. För att uppnå detta måste du skapa en dekoratörsfabrik — en funktion som returnerar en dekoratör. Här är ett exempel på en dekoratör som tar ett argument för att ange ett anpassat meddelande.

def custom_message_decorator(message):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(message)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@custom_message_decorator("Starting the function...")
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Dekoratörer för metoder i klasser

Dekoratörer kan också användas med metoder inom klasser. Vanliga användningsområden inkluderar loggningsmetodanrop, åtkomstkontroll och cachningsresultat. Här är ett exempel på hur man använder en dekoratör för att logga metodanrop i en klass.

def log_method_call(method):
    def wrapper(self, *args, **kwargs):
        print(f"Calling {method.__name__} with arguments {args} and keyword arguments {kwargs}")
        return method(self, *args, **kwargs)
    return wrapper

class MyClass:
    @log_method_call
    def my_method(self, x, y):
        print(f"Result: {x + y}")

obj = MyClass()
obj.my_method(5, 7)

Kedjedekoratörer

Du kan använda flera dekoratörer på en enda funktion. De appliceras från den innersta dekoratören till den yttersta. Detta gör att du kan komponera olika funktioner tillsammans. Här är ett exempel på att kedja två dekoratörer:

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

def exclamation_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result + "!"
    return wrapper

@exclamation_decorator
@uppercase_decorator
def greet(name):
    return f"Hello, {name}"

print(greet("Alice"))

Slutsats

Dekoratörer är ett mångsidigt verktyg i Python som låter dig förbättra eller ändra beteendet hos funktioner och metoder. Genom att använda dekoratörer kan du lägga till återanvändbar funktionalitet över din kodbas utan att ändra kärnlogiken i dina funktioner. Oavsett om det gäller loggning, timing eller modifiering av utdata hjälper dekoratörer till att hålla din kod ren och underhållbar. Träna på att använda dekoratörer för att bli mer skickliga och dra nytta av deras kraft i dina Python-projekt.