Dekoratory w Pythonie
Ten artykuł wyjaśnia dekoratory w Pythonie.
YouTube Video
Dekoratory w Pythonie
Dekoratory Pythona to potężna funkcja, która pozwala dodawać dodatkową funkcjonalność do funkcji lub metod. Dekoratory pozwalają dodać nową funkcjonalność bez modyfikowania istniejącego kodu, co zwiększa jego możliwość ponownego użycia i łatwość utrzymania.
Podstawy dekoratorów
Dekoratory w Pythonie działają poprzez przyjęcie funkcji jako argumentu i zwrócenie nowej funkcji z dodaną funkcjonalnością. Dzięki dekoratorom można łatwo dodać przed- lub post-przetwarzanie do funkcji.
Bez dekoratorów zmiana zachowania funkcji wymaga bezpośredniej edycji samej funkcji. Dzięki dekoratorom można rozszerzyć funkcjonalność bez modyfikowania pierwotnej implementacji.
Podstawowa struktura dekoratora
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()
W tym przykładzie funkcja my_decorator
działa jako dekorator, otaczając funkcję say_hello
. Dekorator jest stosowany za pomocą składni @my_decorator
, a kiedy say_hello()
jest wywoływana, automatycznie wykonywane są działania wstępne i końcowe zapewnione przez dekorator.
Jak działają dekoratory
Dekoratory działają zgodnie z następującymi krokami.
-
Dekorator przyjmuje funkcję (lub metodę) jako argument.
-
Definiuje funkcję osłaniającą, aby wykonać oryginalną funkcję.
-
Funkcja osłaniająca wykonuje dodatkowe przetwarzanie przed lub po wywołaniu oryginalnej funkcji.
-
Dekorator zwraca funkcję osłaniającą. W rezultacie oryginalna funkcja zostaje zastąpiona nową, udekorowaną funkcją.
Dekoratory dla funkcji z argumentami
Podczas stosowania dekoratora do funkcji z argumentami funkcja osłaniająca musi zostać dostosowana do przyjęcia tych argumentów.
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")
Dzięki użyciu *args
i **kwargs
można obsługiwać funkcje przyjmujące dowolną liczbę argumentów i argumentów kluczowych. Pozwala to na stosowanie dekoratorów ogólnie do funkcji z dowolnym typem argumentów.
Przykłady Zastosowania Dekoratorów
Dekorator do Logowania
Dekoratory są często używane do dodania funkcjonalności logowania. Na przykład, tworząc dekorator, który zapisuje logi przed i po wykonaniu funkcji, możesz rejestrować, kiedy funkcja została wywołana i jak długo trwa jej wykonanie.
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)
W tym przykładzie dekorator log_time
mierzy czas wykonania funkcji i zapisuje go jako log. Funkcja long_task
jest opakowana dekoratorem, a jej czas wykonania jest rejestrowany podczas działania.
Dekorator do Zarządzania Uprawnieniami
Dekoratory mogą być również używane do zarządzania uprawnieniami. Na przykład, możesz ograniczyć przetwarzanie, sprawdzając, czy użytkownik ma określone uprawnienia.
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!
Dekorator requires_permission
ogranicza wykonanie funkcji na podstawie roli użytkownika. Ujednolicając taką logikę w dekoratorze, możesz zapobiec rozpraszaniu logiki zarządzania uprawnieniami w kodzie, poprawiając czytelność.
Zagnieżdżanie Dekoratorów
Można zastosować wiele dekoratorów. Kiedy wiele dekoratorów jest zastosowanych do jednej funkcji, wykonują się one w kolejności od góry do dołu.
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!"
W tym przykładzie dwa dekoratory są zastosowane do funkcji greet
. Dekorator @exclaim
dodaje na końcu ciągu znaków wykrzyknik, a @uppercase
zamienia ciąg znaków na wielkie litery.
Dekoratory dla Metod Klas
Dekoratory mogą być również używane z metodami klasowymi. Jest to szczególnie przydatne, gdy chcesz kontrolować zachowanie metod w obrębie klasy. Podczas stosowania dekoratorów do metod klasowych należy zwrócić uwagę na argumenty takie jak self
lub 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")
W tym przykładzie dekorator log_method_call
jest zastosowany do metody greet
, aby zapisać log podczas jej wywołania.
Uwagi dotyczące Dekoratorów
Istnieją pewne kwestie do rozważenia podczas używania dekoratorów. Dekoratory mogą potencjalnie zmienić nazwę i opis oryginalnej funkcji (np. __name__
lub __doc__
), dlatego zaleca się używanie functools.wraps
do zachowania tych informacji.
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
Użycie @functools.wraps
zapewnia poprawne przekazanie metadanych oryginalnej funkcji do funkcji opakowującej.
Podsumowanie
Dekoratory w języku Python to bardzo potężne narzędzie, które umożliwia zwięzłe dodawanie dodatkowej funkcjonalności do funkcji i metod. Mogą być stosowane w różnych scenariuszach, aby zmniejszyć duplikację kodu oraz poprawić jego łatwość utrzymania i ponownego wykorzystania. Rozumiejąc, jak działają dekoratory, możesz pisać bardziej wydajny i elastyczny kod.
Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.