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