2009-11-05 8 views
7

Beim Erstellen von Dekoratoren für Klassenmethoden habe ich Probleme, wenn der Decorator-Mechanismus eine Klasse und keine Funktion/Schließung ist. Wenn das Klassenformular verwendet wird, wird mein Decorator nicht als gebundene Methode behandelt.Python-Dekoratoren für Klassenmitglieder schlagen fehl, wenn der Decorator-Mechanismus eine Klasse ist

Generell bevorzuge ich die Funktion Formular für Dekoratoren, aber in diesem Fall muss ich eine vorhandene Klasse verwenden, um zu implementieren, was ich brauche.

Dies scheint, als ob es mit python-decorator-makes-function-forget-that-it-belongs-to-a-class verwandt sein könnte, aber warum funktioniert es gut für die Funktionsform?

Hier ist das einfachste Beispiel, das ich machen könnte, um alles zu zeigen. Sorry über die Menge an Code:

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) 

Ausgang:

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

Ich würde empfehlen, die Frage umzubenennen. Dies bezieht sich eigentlich nicht auf Dekoratoren, sondern bezieht sich eher auf das Hinzufügen eines Funktionsobjekts als Klassenmethode. – Casebash

+0

Im Allgemeinen (wenn auch nicht immer) kann das Problem durch Isolierung des Problems vereinfacht werden, wenn eine Frage so lang ist. Wenn Sie beispielsweise versucht hätten, die Klasse manuell mit Anmerkungen zu versehen, hätten Sie erkannt, dass sie nichts mit Dekoratoren zu tun hat, und es wäre wahrscheinlich schneller gewesen, als den gesamten Code einzugeben – Casebash

Antwort

10

Ihre WrapperClass Bedürfnisse ein Schlagwort sein (! Ebenso wie eine Funktion ist), das heißt, die Lieferung geeignete spezielle Methoden __get__ und __set__. This how-to guide lehrt alles, was Sie darüber wissen müssen! -)

Verwandte Themen