Классы-декораторы в Python
В этой статье вы узнаете о декораторах классов и научитесь определять классы в качестве декораторов в Python.
В предыдущих статьях мы обсуждали, как использовать функции для определения декораторов.
Например, следующая функция выводит количество символов *
до и после вызова декорированной функции:
def star(n):
def decorate(fn):
def wrapper(*args, **kwargs):
print(n*'*')
result = fn(*args, **kwargs)
print(result)
print(n*'*')
return result
return wrapper
return decorate
Функция star()
— это так называемая фабрика декораторов, которая возвращает декоратор. Фабрика принимает аргумент, задающий количество *
символов, которые нужно вывести.
Вот, как используется эта фабрика декораторов:
@star(5)
def add(a, b):
return a + b
add(10, 20)
Вывод
*****
30
*****
Фабрика декоратора star()
принимает аргумент и возвращает callable-объект. Callable-объект принимает аргумент — некую функцию fn()
, которая будет декорирована. Также callable-объект может получить доступ к аргументу n
, переданному фабрике декораторов.
Экземпляр класса может быть callable, если он реализует метод __call__
. Поэтому метод __call__
можно сделать декоратором.
В следующем примере перепишем фабрика декораторов star
с использованием класса:
class Star:
def __init__(self, n):
self.n = n
def __call__(self, fn):
def wrapper(*args, **kwargs):
print(self.n*'*')
result = fn(*args, **kwargs)
print(result)
print(self.n*'*')
return result
return wrapper
Класс Star
в качестве декоратора можно использовать следующим образом:
@Star(5)
def add(a, b):
return a + b
Функция @Star(5)
возвращает экземпляр класса Star
. Этот экземпляр является вызываемым, поэтому вы можете сделать что-то вроде такого:
add = Star(5)(add)
Соберем все вместе:
from functools import wraps
class Star:
def __init__(self, n):
self.n = n
def __call__(self, fn):
@wraps(fn)
def wrapper(*args, **kwargs):
print(self.n*'*')
result = fn(*args, **kwargs)
print(result)
print(self.n*'*')
return result
return wrapper
@Star(5)
def add(a, b):
return a + b
add(10, 20)
Что нужно запомнить
- Вызываемые классы можно использовать в качестве декораторов, реализовав метод
__call__
. - Аргументы декоратора передаются в метод
__init__
.