Как сделать так, чтобы именно класс мог быть декоратором, а не его экземпляры?
Подскажите, пожалуйста, как сделать такой класс декоратор, чтобы именно он принимал на вход функцию?
Поясню. Вот сейчас у меня есть так называемый класс функтор с переопределённым методом __call__ и его экземпляры могут быть декораторами:
from functools import wraps
class FuncDec:
def __init__(self):
pass
def __call__(self, f):
@wraps(f)
def wrapper(*args, **kwargs):
f(*args, **kwargs)
print('I am working properly')
return wrapper
func_dec = FuncDec()
@func_dec
def func():
print('Hello')
func()
# Hello
# I am working properly
Собственно вопрос в том, как сделать, чтобы я мог декорировать функцию не с помощью (или не только) @func_dec, а с помощью @FuncDec. Я не понимаю, как и что надо прописать в __init__, чтобы декоратором стал именно класс.
Долго рылся в инэте и нашёл почти подходящий пример и не понимаю, почему у них работает, а у меня нет... По сути ведь разница только в том, что в примере декоратор с параметром.
from functools import wraps
class Repeater:
def __init__(self, n):
self.n = n
def __call__(self, f):
@wraps(f)
def wrapper(*args, **kwargs):
for _ in range(self.n):
f(*args, **kwargs)
return wrapper
@Repeater(3)
def foo():
print('foo')
foo()
Заранее большое спасибо!
Ответы (3 шт):
В Repeater(3) декоратор — тоже экземпляр
Так подойдёт?
from functools import wraps
class Repeater:
@staticmethod
def repeat(n):
def inner(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
for _ in range(n):
fn(*args, **kwargs)
return wrapper
return inner
@Repeater.repeat(3)
def foo():
print('foo')
foo()
примерно так:
class FuncDec:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
self.func(*args, **kwargs)
print('I am working properly')
@FuncDec
def func():
print('Hello')
@Repeater(3)
def foo():
print('foo')
foo()
можно записать так:
repeater = Repeater(3)# создаём экземпляр класс
foo = repeater(foo) # в foo записываем функцию wrapper
foo() # вызываем wrapper
а ваш начальный код так:
funcdec = FuncDec() # создаём экземпляр класс
foo = funcdec(foo) # в foo записываем функцию wrapper
foo() # вызываем wrapper
а мой код можно записать так:
foo = FuncDev(foo) # foo становится экземпляром класса FuncDev
foo() # вызываем __call__ нашего класса
в первых двух вариантах в foo лежит wrapper, а в моем варианте экземпляр класса
Поскольку у вас пустой конструктор, то и декоратор вызывается с конструктором. По сути дела, у вас func_dec = FuncDec() заменяется обычным вызовом конструктора с собачкой:
@FuncDec()
def func():
print('Hello')