Dekoratorer i Python

Dekoratorer i Python

Den här artikeln förklarar dekoratorer i Python.

YouTube Video

Dekoratorer i Python

Python-dekoratorer är en kraftfull funktion som används för att lägga till ytterligare funktionalitet till funktioner eller metoder. Dekoratorer gör det möjligt att lägga till ny funktionalitet utan att ändra befintlig kod, vilket förbättrar återanvändbarheten och underhållbarheten av koden.

Grunderna i Dekoratorer

Python-dekoratorer fungerar genom att ta en funktion som argument och returnera en ny funktion med tillagd funktionalitet. Med hjälp av dekoratorer kan du enkelt lägga till förbearbetning eller efterbearbetning till funktioner.

Utan dekoratorer kräver ändring av en funktions beteende att du direkt redigerar funktionen själv. Med dekoratorer kan du utöka funktionaliteten utan att ändra den ursprungliga implementationen.

Grundstrukturen för 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 detta exempel fungerar funktionen my_decorator som en dekorator och omsluter funktionen say_hello. Dekoratorn tillämpas med hjälp av syntaxen @my_decorator, och när say_hello() anropas, körs för- och efterbearbetningen som dekoratorn tillhandahåller automatiskt.

Hur Dekoratorer Fungerar

Dekoratorer fungerar enligt följande steg.

  1. Dekoratorn tar en funktion (eller metod) som argument.

  2. Den definierar en omslutande funktion för att köra den ursprungliga funktionen.

  3. Den omslutande funktionen utför ytterligare bearbetning före eller efter körning av den ursprungliga funktionen.

  4. Dekoratorn returnerar den omslutande funktionen. Som resultat ersätts den ursprungliga funktionen med en ny, dekorerad funktion.

Dekoratorer för Funktioner med Argument

När en dekorator används på en funktion med argument måste den omslutande funktionen justeras för att acceptera dessa argument.

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

Genom att använda *args och **kwargs är det möjligt att hantera funktioner som accepterar ett godtyckligt antal argument och nyckelordsargument. Detta gör det möjligt att använda dekoratorer generiskt på funktioner med vilken typ av argument som helst.

Exempel på att använda dekorerare

Dekorerare för loggning

Dekorerare används ofta för att lägga till loggningsfunktioner. Till exempel, genom att skapa en dekorerare som loggar före och efter att en funktion körs, kan du registrera när funktionen anropas och hur lång tid den tar att köra.

 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 detta exempel mäter dekoreraren log_time en funktions körtid och skriver ut den som en logg. Funktionen long_task är innesluten med dekoreraren, och dess körtid registreras under körning.

Dekorerare för behörighetshantering

Dekorerare kan också användas för behörighetshantering. Till exempel, du kan begränsa bearbetning genom att kontrollera om en användare har specifika behörigheter.

 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!

Dekoreraren requires_permission begränsar körningen av en funktion baserat på en användares roll. Genom att samla sådan logik i en dekorerare kan du förhindra att behörighetshanteringslogik sprids i din kod, vilket förbättrar läsbarheten.

Nästlade dekorerare

Det är möjligt att använda flera dekorerare. När flera dekorerare appliceras på en enda funktion, körs de i ordning från topp till botten.

 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 detta exempel används två dekorerare på funktionen greet. Dekoreraren @exclaim lägger till ett utropstecken i slutet av strängen, och därefter konverterar @uppercase strängen till versaler.

Dekorerare för klassmetoder

Dekorerare kan också användas med klassmetoder. Detta är särskilt användbart när du vill kontrollera beteendet hos metoder inom en klass. När du använder dekorerare på klassmetoder måste du vara uppmärksam på argument 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 detta exempel används dekoreraren log_method_call på metoden greet för att skriva ut en logg när metoden anropas.

Varningar för dekorerare

Det finns vissa överväganden att tänka på när man använder dekorerare. Dekorerare kan potentiellt ändra den ursprungliga funktionens namn och dokumentationssträng (t.ex. __name__ eller __doc__), så det rekommenderas att använda functools.wraps för att bevara denna information.

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

Genom att använda @functools.wraps säkerställs att den ursprungliga funktionens metadata korrekt överförs till omslagningsfunktionen.

Sammanfattning

Python-dekoratorer är ett mycket kraftfullt verktyg som gör det möjligt att på ett kortfattat sätt lägga till ytterligare funktionalitet till funktioner och metoder. De kan användas i olika scenarier för att minska koddupplikation och förbättra underhållbarhet och återanvändbarhet. Genom att förstå hur dekoratorer fungerar kan du skriva mer effektiv och flexibel kod.

Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.

YouTube Video