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.
-
Dekoratorn tar en funktion (eller metod) som argument.
-
Den definierar en omslutande funktion för att köra den ursprungliga funktionen.
-
Den omslutande funktionen utför ytterligare bearbetning före eller efter körning av den ursprungliga funktionen.
-
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.