Wie kann ich dekorieren Sie eine Instanz-Methode mit einem decorator-Klasse?
Betrachten dieses kleine Beispiel:
import datetime as dt
class Timed(object):
def __init__(self, f):
self.func = f
def __call__(self, *args, **kwargs):
start = dt.datetime.now()
ret = self.func(*args, **kwargs)
time = dt.datetime.now() - start
ret["time"] = time
return ret
class Test(object):
def __init__(self):
super(Test, self).__init__()
@Timed
def decorated(self, *args, **kwargs):
print(self)
print(args)
print(kwargs)
return dict()
def call_deco(self):
self.decorated("Hello", world="World")
if __name__ == "__main__":
t = Test()
ret = t.call_deco()
dem Drucke
Hello
()
{'world': 'World'}
Warum ist die self
parameter (das sollten die Test obj-Instanz) nicht bestanden, der als erstes argument an die eingerichtete Funktion decorated
?
Wenn ich es manuell mache, wie :
def call_deco(self):
self.decorated(self, "Hello", world="World")
funktioniert es wie erwartet. Aber wenn ich muss im Voraus wissen, ob eine Funktion eingerichtet ist oder nicht, es Niederlagen der ganze Zweck der Dekorateure. Was ist das Muster, hier zu gehen, oder mache ich etwas falsch verstanden?
Eine schnelle google auftaucht: thecodeship.com/patterns/guide-to-python-function-decorators (siehe Abschnitt "Dekorieren Methoden")
Haben Sie gelesen, z.B. stackoverflow.com/q/2365701/3001761, stackoverflow.com/q/15098424/3001761
Du wirst nicht auf diese Art von problem, wenn Sie eine Funktion als Dekorator statt eines callable-Objekts.
Haben Sie gelesen, z.B. stackoverflow.com/q/2365701/3001761, stackoverflow.com/q/15098424/3001761
Du wirst nicht auf diese Art von problem, wenn Sie eine Funktion als Dekorator statt eines callable-Objekts.
InformationsquelleAutor Rafael T | 2015-05-07
Du musst angemeldet sein, um einen Kommentar abzugeben.
tl;dr
Dieses problem können Sie beheben, indem Sie die
Timed
Klasse a Deskriptor und die Rückgabe einer partiell angewandten Funktion von__get__
gilt dieTest
Objekt als eines der Argumente, wie dieseDas eigentliche problem
Zitieren Python-Dokumentation für Dekorator,
So, wenn Sie sagen,
ist es eigentlich
nur die Funktion ein Objekt übergeben, um die
Timed
, das Objekt, zu dem es tatsächlich gebunden ist, nicht an, zusammen mit. Also, wenn Sie es aufrufen, wie diesself.func
beziehen sich auf die ungebundene Funktion Objekt und es wird aufgerufen mitHello
wie das erste argument. Das ist, warumself
Drucke alsHello
.Wie kann ich dieses Problem beheben?
Da Sie keinen Verweis auf die
Test
Instanz in derTimed
, der einzige Weg, dies zu tun wäre, um zu konvertierenTimed
als - Deskriptor-Klasse. Angabe der Unterlagen, Aufruf-Deskriptoren Abschnitt,Können wir machen
Timed
einen Deskriptor, indem Sie einfach die Definition einer Methode, wie dieseHier
self
bezieht sich auf dieTimed
Objekt selbstinstance
bezieht sich auf das aktuelle Objekt, auf dem der Attribut-lookup geschieht, undowner
bezieht sich auf die Klasse entsprechend derinstance
.Nun, wenn
__call__
aufgerufen wirdTimed
, die__get__
- Methode aufgerufen wird. Nun, irgendwie müssen wir die ersten argument die Instanz desTest
Klasse (noch vorHello
). Wir erstellen also ein anderes partiell angewandte Funktion, deren Erster parameter wird dieTest
Instanz, wie diesNun
self.__call__
ist eine gebundene Methode (gebundenTimed
Instanz) und der zweite parameterpartial
ist das erste argument für dieself.__call__
nennen.So, all diese effektiv zu übersetzen, wie dies
Nun
self.decorated
ist eigentlichTimed(decorated)
(dies wird bezeichnet alsTimedObject
von nun an) Objekt. Wenn wir darauf zugreifen, die__get__
Methode definiert ist, wird Sie aufgerufen, und es gibt einepartial
Funktion. Können Sie bestätigen, dass, wie diesdrucken würde
So,
übersetzt wird, zu
Da kehren wir ein
partial
Funktion,was ist eigentlich
So,
<Test obj>
wird auch ein Teil der*args
, und wennself.func
ist aufgerufen, das erste argument wird sein, die<Test obj>
.functool.partial
anstelle des integrierten dediziertentypes.MethodType
?Vielen Dank für diese umfassende Antwort - ich werde es Lesen ein paar mal zu grok, aber ich bin zuversichtlich, dass ich werde! Als ich zuerst versucht, die Anwendung dieser, ich Links von der
(object)
in der definition von meinem decorator - so, ich hatte geradeclass Timed:
- und ich habe immer noch die OP ' s ursprüngliche Fehler. Könnten Sie mir auf das richtige Konzept zu Lesen, um zu verstehen, warum?Waren Sie in Python2.7? 2.7 Sie wollen, stellen Sie sicher, jede Klasse erbt von
object
; diese Vererbung ist standardmäßig in Python ist3. Ich weiß nicht, konkret, warum dies manifestiert sich in einem bug, aber das ist die wahrscheinlich Täter -type(YourClass)
solltetype
, nichtclassobj
.Können Sie bitte erklären, warum
def check_authorization(f): def wrapper(*args): print(args[0].url) return f(*args) return wrapper class Client(object): def __init__(self, url): self.url = url @check_authorization def get(self): print('get')
hier funktioniert? wäre es nicht auch ungebunden?InformationsquelleAutor thefourtheye
Müssen Sie zunächst verstehen,wie die Funktion zu Methoden und wie
self
"automagisch" injiziert.Sobald Sie wissen, dass das "problem" liegt auf der Hand: Sie schmücken die
decorated
Funktion mit einemTimed
Instanz - IOW,Test.decorated
ist einTimed
Instanz, nicht einefunction
Instanz - und IhrTimed
Klasse nicht imitieren diefunction
geben Sie die Implementierung derdescriptor
Protokoll. Was Sie wollen, sieht wie folgt aus:MethodType
nur zwei Argumente nimmt, und die zweite darf nicht sein, Keiner). Für Python 3 die alternative wäre:return types.MethodType(self, instance) if instance else self
.InformationsquelleAutor bruno desthuilliers
Benutze ich Dekorateure in der folgenden Weise:
InformationsquelleAutor PyNico