Como faço para que decoradores baseados em classe funcionem, por exemplo, métodos? [duplicado]
Esta pergunta já tem uma resposta aqui:
Usando classes como decoradores de métodos [duplicado] 1 respostaExistem duas maneiras de chamar os decoradores: 1) passando a função / classe do decorador
class Foo(object):
def __init__(self):
self.x = 1
@foo_decorator
def bar(self, x):
return self.x + x
ou 2) passando o valor de retorno da função decoradora / instância de classe.
class Foo(object):
def __init__(self):
self.x = 1
@foo_decorator("args")
def bar(self, x):
return self.x + x
A questão é: como faço para que o decorador funcione nos dois casos, já que preciso implementar o decorador usando o método baseado em classe?
Um exemplo dessa implementação seria
import functools
class FooDecorator(object):
def __init__(self, *args):
if len(args) == 1 and callable(args[0]):
self.f = args[0]
functools.update_wrapper(self, args[0])
else:
self.f = None
def __call__(self, *args, **kwargs):
if self.f is not None:
return self.f(*args, **kwargs)
else:
assert len(args) >= 1 and callable(args[0])
f = args[0]
self.f = f
functools.update_wrapper(self, f)
return self
foo_decorator = FooDecorator
No entanto, testar essa implementação simples usando o código a seguir gera alguns erros:
class Foo1(object):
def __init__(self):
self.x = 1
@foo_decorator
def bar(self, x):
return self.x + x
class Foo2(object):
def __init__(self):
self.x = 1
@foo_decorator("args")
def bar(self, x):
return self.x + x
Foos = [Foo1, Foo2]
for i in range(2):
print(Foos[i].__name__)
f = Foos[i]()
print(f.bar(10))
Traceback (most recent call last):
File "python", line 47, in <module>
File "python", line 13, in __call__
TypeError: bar() missing 1 required positional argument: 'x'
Isso foi testado no python 2.7 e 3.5.
Qualquer ajuda é apreciada. Observe que eu já pesquisei completamente a web inteira e já li os seguintes artigos sobre o assunto:
Graham Dumpleton: Como você implementou seu decorador Python está errado.decorator
pacote na documentação do PyPIObserve também quedecorator
O pacote não suporta o segundo método para incorrer em decoradores (pré-inicializando objetos do decorador) que eu saiba.