Продвинутые техники и сценарии использования декораторов
Как вы уже видели, декораторы - это мощный инструмент для изменения поведения функций в Python. В этом разделе мы рассмотрим некоторые более продвинутые техники и сценарии использования декораторов.
Декорирование классов
Декораторы также можно использовать для изменения поведения классов. Вот пример декоратора, который добавляет метод логирования в класс:
def log_class_methods(cls):
class LoggedClass(cls):
def __getattribute__(self, attr):
if callable(super(LoggedClass, self).__getattribute__(attr)):
def logged_method(*args, **kwargs):
print(f"Calling method {attr}")
return super(LoggedClass, self).__getattribute__(attr)(*args, **kwargs)
return logged_method
return super(LoggedClass, self).__getattribute__(attr)
return LoggedClass
@log_class_methods
class MyClass:
def __init__(self, value):
self.value = value
def do_something(self):
print(f"Doing something with value: {self.value}")
obj = MyClass(42)
obj.do_something() ## Output: Calling method do_something
## Doing something with value: 42
В этом примере декоратор log_class_methods
принимает класс в качестве аргумента и возвращает новый класс, который оборачивает все методы исходного класса функцией логирования.
Декораторы с состоянием
Декораторы также могут сохранять состояние между вызовами функций. Это может быть полезно для кэширования, ограничения скорости или других операций, связанных с состоянием. Вот пример декоратора, который кэширует результаты функции:
def cache(func):
cache = {}
def wrapper(*args):
if args in cache:
print("Returning cached result")
return cache[args]
else:
result = func(*args)
cache[args] = result
return result
return wrapper
@cache
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) ## Output: Calculating fibonacci(10)
## 55
print(fibonacci(10)) ## Output: Returning cached result
## 55
В этом примере декоратор cache
сохраняет словарь аргументов вызовов функции и соответствующих им результатов. Когда вызывается декорированная функция, декоратор сначала проверяет, есть ли результат уже в кэше, и если да, возвращает кэшированный результат. В противном случае он вычисляет результат и сохраняет его в кэше для дальнейшего использования.
Фабрики декораторов
Иногда вы можете захотеть создать декораторы, которые можно настроить с помощью аргументов. Это можно достичь с использованием фабрики декораторов, которая представляет собой функцию, возвращающую декоратор. Вот пример:
def repeat(n):
def decorator(func):
def wrapper():
result = ""
for _ in range(n):
result += func()
return result
return wrapper
return decorator
@repeat(3)
def say_hello():
return "hello "
print(say_hello()) ## Output: hello hello hello
В этом примере функция repeat
является фабрикой декораторов, которая принимает аргумент n
и возвращает декоратор, который оборачивает исходную функцию, вызывая ее n
раз и объединяя результаты.
Эти продвинутые техники использования декораторов демонстрируют гибкость и мощь декораторов в Python. Используя декораторы, вы можете создавать переиспользуемый, модульный и легко поддерживаемый код, который можно легко расширять и настраивать в соответствии с вашими потребностями.