6.1 Dekoratory metod klas
Dekoratory mogą być również używane do metod klas. Ważne jest, aby pamiętać, że dla metod klas należy poprawnie przekazywać argumenty self
lub cls
.
Niestety nie omawialiśmy jeszcze szczegółów działania klas, ale chcielibyśmy, abyście wiedzieli, że dekoratory mają taką możliwość.
def log_method_call(func):
def wrapper(self, *args, **kwargs):
print(f"Wywołanie metody {func.__name__}")
return func(self, *args, **kwargs)
return wrapper
class MyClass:
@log_method_call
def say_hello(self):
print("Hello from MyClass!")
obj = MyClass()
obj.say_hello()
Wyjaśnienie
Dekorator (log_method_call)
: Ten dekorator przyjmuje metodę func
i zwraca nową funkcję wrapper
, która wyświetla komunikat przed wywołaniem metody.
Metoda klasy z dekoratorem (say_hello)
: Metoda say_hello
jest opakowana w dekorator log_method_call
, co dodaje dodatkowe zachowanie podczas jej wywołania.
Wynik:
Wywołanie metody say_hello
Hello from MyClass!
6.2 Kilka dekoratorów
Możesz używać kilku dekoratorów dla jednej funkcji, nakładając je na siebie. Dekoratory stosuje się w odwrotnej kolejności niż są zadeklarowane.
def decorator1(func):
def wrapper():
print("Dekorator 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Dekorator 2")
func()
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
say_hello()
Wyjaśnienie
Dekoratory (decorator1 i decorator2)
: Te dekoratory dodają swoje komunikaty przed wywołaniem funkcji func
.
Funkcja z dekoratorami (say_hello)
: Funkcja say_hello
jest opakowana w oba dekoratory. Najpierw zastosowany jest decorator2
, potem decorator1
.
Wynik:
# Dekorator 1
# Dekorator 2
Hello!
6.3 Wbudowane dekoratory
Python udostępnia kilka wbudowanych dekoratorów do standardowych zadań, takich jak metody statyczne, metody klasowe i właściwości.
@staticmethod
Dekorator @staticmethod
jest używany do tworzenia metody statycznej, która nie wymaga instancji klasy do jej wywołania.
class MyClass:
@staticmethod
def static_method():
print("To jest metoda statyczna.")
MyClass.static_method()
@classmethod
Dekorator @classmethod
jest używany do tworzenia metody klasowej, która przyjmuje klasę (a nie instancję) jako pierwszy argument.
class MyClass:
@classmethod
def class_method(cls):
print(f"To jest metoda klasy {cls.__name__}.")
MyClass.class_method()
@property
Dekorator @property
jest używany do tworzenia getterów, setterów i deleterów dla atrybutów.
class MyClass:
def __init__(self, value):
self.hidden_value = value
@property
def value(self):
return self.hidden_value
@value.setter
def value(self, new_value):
self.hidden_value = new_value
obj = MyClass(10)
print(obj.value) # Wynik: 10
obj.value = 20
print(obj.value) # Wynik: 20
To są wbudowane dekoratory, a ich poprawne działanie zapewnia sam interpreter Pythona.
6.4 Przykłady użycia dekoratorów
Logowanie
Dekoratory mogą być używane do logowania wywołań funkcji i metod.
def log_call(func):
def wrapper(*args, **kwargs):
print(f"Wywołanie funkcji {func.__name__} z argumentami {args} i {kwargs}")
return func(*args, **kwargs)
return wrapper
@log_call
def add(x, y):
return x + y
print(add(2, 3))
Kontrola dostępu
Dekoratory mogą być używane do kontroli dostępu do funkcji i metod.
def require_authentication(func):
def wrapper(*args, **kwargs):
if not args[0].is_authenticated:
raise PermissionError("Użytkownik nie jest uwierzytelniony.")
return func(*args, **kwargs)
return wrapper
class User:
def __init__(self, is_authenticated):
self.is_authenticated = is_authenticated
@require_authentication
def view_profile(self):
print("Profil użytkownika")
user = User(is_authenticated=True)
user.view_profile() # Pomyślne wywołanie
user2 = User(is_authenticated=False)
user2.view_profile() # PermissionError: Użytkownik nie jest uwierzytelniony.
Buforowanie
Dekoratory mogą być używane do buforowania wyników funkcji.
def cache(func):
cached_results = {}
def wrapper(*args):
if args in cached_results:
return cached_results[args]
result = func(*args)
cached_results[args] = result
return result
return wrapper
@cache
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(fib(35))
GO TO FULL VERSION