Al crear decoradores para usar en métodos de clase, tengo problemas cuando el mecanismo decorador es una clase en lugar de una función/cierre. Cuando se utiliza el formulario de clase, mi decorador no se trata como un método vinculado.Los decoradores de Python en los miembros de la clase fallan cuando el mecanismo decorador es una clase
Generalmente prefiero usar el formulario de función para decoradores, pero en este caso tengo que usar una clase existente para implementar lo que necesito.
Parece que podría estar relacionado con python-decorator-makes-function-forget-that-it-belongs-to-a-class, pero ¿por qué funciona bien para el formulario de función?
Aquí está el ejemplo más simple que podría hacer para mostrar todo lo que sucede. Lo sentimos acerca de la cantidad de código:
def decorator1(dec_param):
def decorator(function):
print 'decorator1 decoratoring:', function
def wrapper(*args):
print 'wrapper(%s) dec_param=%s' % (args, dec_param)
function(*args)
return wrapper
return decorator
class WrapperClass(object):
def __init__(self, function, dec_param):
print 'WrapperClass.__init__ function=%s dec_param=%s' % (function, dec_param)
self.function = function
self.dec_param = dec_param
def __call__(self, *args):
print 'WrapperClass.__call__(%s, %s) dec_param=%s' % (self, args, self.dec_param)
self.function(*args)
def decorator2(dec_param):
def decorator(function):
print 'decorator2 decoratoring:', function
return WrapperClass(function, dec_param)
return decorator
class Test(object):
@decorator1(dec_param=123)
def member1(self, value=1):
print 'Test.member1(%s, %s)' % (self, value)
@decorator2(dec_param=456)
def member2(self, value=2):
print 'Test.member2(%s, %s)' % (self, value)
@decorator1(dec_param=123)
def free1(value=1):
print 'free1(%s)' % (value)
@decorator2(dec_param=456)
def free2(value=2):
print 'free2(%s)' % (value)
test = Test()
print '\n====member1===='
test.member1(11)
print '\n====member2===='
test.member2(22)
print '\n====free1===='
free1(11)
print '\n====free2===='
free2(22)
Salida:
decorator1 decoratoring: <function member1 at 0x3aba30>
decorator2 decoratoring: <function member2 at 0x3ab8b0>
WrapperClass.__init__ function=<function member2 at 0x3ab8b0> dec_param=456
decorator1 decoratoring: <function free1 at 0x3ab9f0>
decorator2 decoratoring: <function free2 at 0x3ab970>
WrapperClass.__init__ function=<function free2 at 0x3ab970> dec_param=456
====member1====
wrapper((<__main__.Test object at 0x3af5f0>, 11)) dec_param=123
Test.member1(<__main__.Test object at 0x3af5f0>, 11)
====member2====
WrapperClass.__call__(<__main__.WrapperClass object at 0x3af590>, (22,)) dec_param=456
Test.member2(22, 2) <<<- Badness HERE!
====free1====
wrapper((11,)) dec_param=123
free1(11)
====free2====
WrapperClass.__call__(<__main__.WrapperClass object at 0x3af630>, (22,)) dec_param=456
free2(22)
Aconsejaría el cambio de nombre de la pregunta. En realidad, esto no está realmente relacionado con los decoradores, sino más bien agregar un objeto de función como método de clase – Casebash
Generalmente (aunque no siempre), cuando una pregunta es tan larga, se puede simplificar aislando el problema. Por ejemplo, si hubiera intentado anotar manualmente la clase, se habría dado cuenta de que no tenía nada que ver con decoradores y probablemente hubiera sido más rápido que escribir todo ese código. – Casebash