Dekoratorer i Python

Dekoratorer i Python

Denne artikel forklarer dekoratorer i Python.

YouTube Video

Dekoratorer i Python

Python-dekoratorer er en kraftfuld funktion, der bruges til at tilføje yderligere funktionalitet til funktioner eller metoder. Dekoratorer giver dig mulighed for at tilføje ny funktionalitet uden at ændre eksisterende kode, hvilket forbedrer kodegenbrug og vedligeholdelse.

Grundlæggende om Dekoratorer

Python-dekoratorer fungerer ved at tage en funktion som argument og returnere en ny funktion med tilføjet funktionalitet. Ved at bruge dekoratorer kan du nemt tilføje forbehandling eller efterbehandling til funktioner.

Uden dekoratorer kræver ændring af en funktions adfærd, at funktionen redigeres direkte. Med dekoratorer kan du udvide funktionaliteten uden at ændre den oprindelige implementering.

Grundlæggende Struktur for en Dekorator

 1def my_decorator(func):
 2    def wrapper():
 3        print("Before the function call")
 4        func()
 5        print("After the function call")
 6    return wrapper
 7
 8@my_decorator
 9def say_hello():
10    print("Hello!")
11
12say_hello()

I dette eksempel fungerer my_decorator-funktionen som en dekorator, der indpakker say_hello-funktionen. Dekoratoren anvendes ved hjælp af syntaksen @my_decorator, og når say_hello() kaldes, udføres for- og efterbehandlingen fra dekoratoren automatisk.

Hvordan Dekoratorer Fungerer

Dekoratorer fungerer i følgende trin.

  1. Dekoratoren tager en funktion (eller metode) som et argument.

  2. Den definerer en wrapper-funktion til at udføre den oprindelige funktion.

  3. Wrapper-funktionen udfører yderligere behandling før eller efter den oprindelige funktion udføres.

  4. Dekoratoren returnerer wrapper-funktionen. Som et resultat erstattes den oprindelige funktion med en ny, dekoreret funktion.

Dekoratorer til Funktioner med Argumenter

Når en dekorator anvendes på en funktion med argumenter, skal wrapper-funktionen justeres til at acceptere disse argumenter.

 1def my_decorator(func):
 2    def wrapper(*args, **kwargs):
 3        print("Before the function call")
 4        result = func(*args, **kwargs)
 5        print("After the function call")
 6        return result
 7    return wrapper
 8
 9@my_decorator
10def greet(name):
11    print(f"Hello, {name}!")
12
13greet("Alice")

Ved at bruge *args og **kwargs er det muligt at håndtere funktioner, der accepterer et vilkårligt antal argumenter og nøgleord-argumenter. Dette gør det muligt at anvende dekoratorer generisk på funktioner med enhver type argumenter.

Eksempler på anvendelse af dekoratorer

Dekorator til logning

Dekoratorer bruges ofte til at tilføje logningsfunktionalitet. For eksempel kan du ved at oprette en dekorator, der logger før og efter udførelse af en funktion, registrere, hvornår funktionen kaldes, og hvor lang tid udførelsen tager.

 1import time
 2
 3def log_time(func):
 4    def wrapper(*args, **kwargs):
 5        start_time = time.time()
 6        print(f"Calling function '{func.__name__}'...")
 7        result = func(*args, **kwargs)
 8        end_time = time.time()
 9        print(f"Function '{func.__name__}' completed in {end_time - start_time} seconds")
10        return result
11    return wrapper
12
13@log_time
14def long_task(duration):
15    time.sleep(duration)
16    print("Task completed!")
17
18long_task(2)

I dette eksempel måler log_time-dekoratoren en funktions udførelsestid og logger den. Funktionen long_task er pakket ind i dekoratoren, og dens udførelsestid registreres under kørsel.

Dekorator til rettighedsstyring

Dekoratorer kan også bruges til rettighedsstyring. For eksempel kan du begrænse behandling ved at kontrollere, om en bruger har specifikke rettigheder.

 1def requires_permission(user_role):
 2    def decorator(func):
 3        def wrapper(*args, **kwargs):
 4            if user_role != "admin":
 5                print("Permission denied!")
 6                return
 7            return func(*args, **kwargs)
 8        return wrapper
 9    return decorator
10
11@requires_permission("admin")
12def delete_user(user_id):
13    print(f"User {user_id} has been deleted.")
14
15delete_user(123)  # Executed
16delete_user = requires_permission("guest")(delete_user)
17delete_user(456)  # Permission denied!

Dekoratoren requires_permission begrænser udførelsen af en funktion baseret på en brugers rolle. Ved at samle sådan logik i en dekorator kan du undgå, at rettighedsstyringslogik spredes i din kode, hvilket forbedrer læsbarheden.

Indlejrede dekoratorer

Det er muligt at anvende flere dekoratorer. Når flere dekoratorer anvendes på en funktion, udføres de i rækkefølge fra top til bund.

 1def uppercase(func):
 2    def wrapper(*args, **kwargs):
 3        result = func(*args, **kwargs)
 4        return result.upper()
 5    return wrapper
 6
 7def exclaim(func):
 8    def wrapper(*args, **kwargs):
 9        result = func(*args, **kwargs)
10        return result + "!"
11    return wrapper
12
13@uppercase
14@exclaim
15def greet(name):
16    return f"Hello, {name}"
17
18print(greet("Alice"))  # "HELLO, ALICE!"

I dette eksempel anvendes to dekoratorer på funktionen greet. @exclaim-dekoratoren tilføjer et udråbstegn til slutningen af strengen, og derefter omdanner @uppercase strengen til store bogstaver.

Dekoratorer til klassens metoder

Dekoratorer kan også bruges med klassens metoder. Dette er især nyttigt, når du vil styre adfærden af metoder inden for en klasse. Når du anvender dekoratorer på klassens metoder, skal du være opmærksom på argumenter som self eller cls.

 1def log_method_call(func):
 2    def wrapper(self, *args, **kwargs):
 3        print(f"Calling method '{func.__name__}'...")
 4        return func(self, *args, **kwargs)
 5    return wrapper
 6
 7class MyClass:
 8    @log_method_call
 9    def greet(self, name):
10        print(f"Hello, {name}")
11
12obj = MyClass()
13obj.greet("Bob")

I dette eksempel anvendes dekoratoren log_method_call på metoden greet for at udføre en log, når metoden kaldes.

Forholdsregler ved dekoratorer

Der er nogle overvejelser ved brug af dekoratorer. Dekoratorer kan ændre den oprindelige funktionens navn og dokumentationsstreng (f.eks. __name__ eller __doc__), så det anbefales at bruge functools.wraps for at bevare disse oplysninger.

1import functools
2
3def my_decorator(func):
4    @functools.wraps(func)
5    def wrapper(*args, **kwargs):
6        print("Before the function call")
7        return func(*args, **kwargs)
8    return wrapper

Brugen af @functools.wraps sikrer, at metadataene for den oprindelige funktion korrekt overføres til wrapper-funktionen.

Sammendrag

Python-dekoratorer er et meget kraftfuldt værktøj, der gør det muligt at tilføje ekstra funktionalitet til funktioner og metoder på en kortfattet måde. De kan bruges i forskellige scenarier til at reducere kode-duplikation og forbedre vedligeholdelse og genanvendelighed. Ved at forstå, hvordan dekoratorer fungerer, kan du skrive mere effektiv og fleksibel kode.

Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.

YouTube Video