class Validation:
def __init__(self, lower, upper):
self._lower = lower
self._upper = upper
def __call__(self, arg):
def wrapper(a):
res = arg(a)
if not self._lower < res < self._upper:
raise ValueError(
'Validation failed'
)
return f'{datetime.now()}: {res}'
return wrapper
@Validation(0, 10)
def square(a):
return a**2
print(square(2))
# 2022-10-29 09:41:59.377104: 4
print(square(4))
# ValueError: Validation failed
Теперь можно передавать границы интервала напрямую в декоратор.
Классами-декораторами можно декорировать как функции, так и другие классы. Они часто встречаются в модулях, и легко отличаются от обычных тем, что их названия записаны в стиле CamelCase.
Второй пример. Создадим декоратор для вычисления значения производной функции в определенной точке x с использованием класса.
class Derivate:
def __init__(self, func):
self.__fn = func
def __call__(self, x, dx=0.0001, *args, **kwargs):
return (self.__fn(x + dx) - self.__fn(x)) / dx
Здесь в инициализаторе сохраняем ссылку на функцию, которую декорируем, а в методе __call__ принимаем один обязательный параметр x – точку, где вычисляется производная и dx – шаг изменения при вычислении производной.
Далее, определим функцию, например, синус:
def df_sin(x):
return math.sin(x)
и вызове ее пока без декорирования:
print(df_sin(math.pi/4))
После запуска программы увидим значение примерно 0.7071.
Добавим декоратор. Это можно сделать двумя способами. Первый, прописать все в явном виде:
df_sin = Derivate(df_sin)
Теперь df_sin – это экземпляр класса Derivate, а не исходная функция. Поэтому, когда она будет вызываться, то запустится метод __call__ и вычислится значение производной в точке math.pi/4.
Второй способ – это воспользоваться оператором @ перед объявлением функции:
@Derivate
def df_sin(x):
return math.sin(x)
Получим абсолютно тот же самый результат. Вот принцип создания декораторов функций на основе классов: запоминаем ссылку на функцию, а затем, расширяем ее функционал в методе __call__.
Функторы бывают очень полезны. Они значительно более гибкие, чем функции, поскольку могут содержать дополнительные атрибуты и методы, наследоваться от других классов и иметь наследников. Особо важно то, что функторы могут выступать в роли декораторов, дополняя функциональность функций и классов.
Достарыңызбен бөлісу: |