Quando si creano decoratori da utilizzare su metodi di classe, ho problemi quando il meccanismo decoratore è una classe piuttosto che una funzione/chiusura. Quando viene utilizzato il modulo di classe, il mio decoratore non viene trattato come metodo associato.I decoratori Python sui membri della classe falliscono quando il meccanismo decoratore è una classe
In genere preferisco utilizzare il modulo di funzione per decoratori ma in questo caso devo utilizzare una classe esistente per implementare ciò di cui ho bisogno.
Questo sembra che potrebbe essere correlato a python-decorator-makes-function-forget-that-it-belongs-to-a-class ma perché funziona bene per il modulo di funzione?
Ecco l'esempio più semplice che potrei fare per mostrare tutto ciò che succede. Mi dispiace per la quantità di codice:
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)
uscita:
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)
Vorrei raccomandare di rinominare la domanda. Questo in realtà non è realmente correlato ai decoratori, ma piuttosto riguarda l'aggiunta di un oggetto funzione come metodo di classe – Casebash
Generalmente (anche se non sempre), quando una domanda è così lunga, può essere semplificata isolando il problema. Ad esempio, se avessi provato a annotare manualmente la classe, ti saresti reso conto che non aveva nulla a che fare con i decoratori e probabilmente sarebbe stato più veloce di digitare tutto quel codice – Casebash