2009-11-05 14 views
7

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) 
+1

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

+0

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

risposta

10

vostre WrapperClass deve essere un descrittore (! Proprio come una funzione è), vale a dire, la fornitura metodi speciali adeguati __get__ e __set__. This how-to guide insegna tutto ciò che è necessario sapere a riguardo! -)

Problemi correlati