Ich habe ein Problem mit der Übertragung der Variablen 'insurance_mode' durch den Dekorateur. Ich würde es mit der folgenden Dekorateuraussage tun:
@execute_complete_reservation(True)
def test_booking_gta_object(self):
self.test_select_gta_object()
aber leider funktioniert diese Aussage nicht. Vielleicht gibt es einen besseren Weg, um dieses Problem zu lösen.
def execute_complete_reservation(test_case,insurance_mode):
def inner_function(self,*args,**kwargs):
self.test_create_qsf_query()
test_case(self,*args,**kwargs)
self.test_select_room_option()
if insurance_mode:
self.test_accept_insurance_crosseling()
else:
self.test_decline_insurance_crosseling()
self.test_configure_pax_details()
self.test_configure_payer_details
return inner_function
execute_complete_reservation
nimmt zwei Parameter, aber Sie übergeben es einen. Dekorateure sind nur syntaktischer Zucker, um Funktionen in andere Funktionen zu verpacken. Eine vollständige Dokumentation finden Sie unter docs.python.org/reference/compound_stmts.html#function .Antworten:
Die Syntax für Dekoratoren mit Argumenten ist etwas anders - der Dekorator mit Argumenten sollte eine Funktion zurückgeben, die eine Funktion übernimmt und eine andere Funktion zurückgibt. Es sollte also wirklich einen normalen Dekorateur zurückgeben. Ein bisschen verwirrend, oder? Was ich meine ist:
Hier können Sie mehr zu diesem Thema lesen - es ist auch möglich, dies mit aufrufbaren Objekten zu implementieren, und das wird auch dort erklärt.
quelle
return function(*args, **kwargs)
@decorator()
und nicht nur verwenden@decorator
, auch wenn Sie nur optionale Argumente haben.Bearbeiten : Um ein umfassendes Verständnis des mentalen Modells von Dekorateuren zu erhalten, werfen Sie einen Blick auf diesen fantastischen Pycon Talk. lohnt sich die 30 Minuten.
Eine Art, über Dekorateure mit Argumenten nachzudenken, ist
wird übersetzt in
Also, wenn der Dekorateur Argumente hatte,
wird übersetzt in
decorator_with_args
ist eine Funktion, die ein benutzerdefiniertes Argument akzeptiert und den tatsächlichen Dekorator zurückgibt (der auf die dekorierte Funktion angewendet wird).Ich benutze einen einfachen Trick mit Teiltönen, um meine Dekorateure einfach zu machen
Aktualisieren:
Über,
foo
wirdreal_decorator(foo)
Ein Effekt beim Dekorieren einer Funktion besteht darin, dass der Name
foo
bei der Deklaratordeklaration überschrieben wird.foo
wird von allem "überschrieben", was von zurückgegeben wirdreal_decorator
. In diesem Fall ein neues Funktionsobjekt.Alle
foo
Metadaten werden überschrieben, insbesondere die Dokumentzeichenfolge und der Funktionsname.functools.wraps bietet uns eine bequeme Methode, um die Dokumentzeichenfolge und den Namen zur zurückgegebenen Funktion zu "heben".
quelle
@functools.wraps
?functool.wraps
. Das Hinzufügen im Beispiel kann die Leser weiter verwirren.arg
hier?bar
an das Argument von übergebene Argument weitergebenreal_decorator
?Ich möchte eine Idee zeigen, die meiner Meinung nach ziemlich elegant ist. Die von t.dubrownik vorgeschlagene Lösung zeigt ein Muster, das immer das gleiche ist: Sie benötigen die dreischichtige Hülle, unabhängig davon, was der Dekorateur tut.
Also dachte ich, das ist ein Job für einen Meta-Dekorateur, das heißt einen Dekorateur für Dekorateure. Da ein Dekorateur eine Funktion ist, arbeitet er tatsächlich als normaler Dekorateur mit Argumenten:
Dies kann auf einen normalen Dekorateur angewendet werden, um Parameter hinzuzufügen. Nehmen wir zum Beispiel an, wir haben den Dekorateur, der das Ergebnis einer Funktion verdoppelt:
Mit können
@parametrized
wir einen generischen@multiply
Dekorator mit einem Parameter erstellenHerkömmlicherweise der erste Parameter eines parametrisierten Dekorators die Funktion, während die verbleibenden Argumente dem Parameter des parametrisierten Dekorators entsprechen.
Ein interessantes Anwendungsbeispiel könnte ein typsicherer, durchsetzungsfähiger Dekorateur sein:
Ein letzter Hinweis: Hier verwende ich nicht
functools.wraps
für die Wrapper-Funktionen, aber ich würde empfehlen, sie immer zu verwenden.quelle
@wraps
meine für meinen speziellen Fall anrufen .@parametrized
Trick. Das Problem, das ich hatte, war, dass ich vergessen habe, dass die@
Syntax den tatsächlichen Aufrufen entspricht (irgendwie wusste ich das und wusste das nicht zur gleichen Zeit, wie Sie meiner Frage entnehmen können). Wenn Sie also die@
Syntax in weltliche Aufrufe übersetzen möchten, um zu überprüfen, wie sie funktioniert, sollten Sie sie zuerst vorübergehend auskommentieren, oder Sie würden sie am Ende zweimal aufrufen und mumbojumbo-Ergebnisse erhaltenHier ist eine leicht modifizierte Version der Antwort von t.dubrownik . Warum?
Verwenden Sie also
@functools.wraps()
:quelle
Ich nehme an, Ihr Problem besteht darin, Ihrem Dekorateur Argumente zu übermitteln. Dies ist etwas schwierig und nicht einfach.
Hier ist ein Beispiel dafür:
Drucke:
Weitere Informationen finden Sie im Artikel von Bruce Eckel.
quelle
__name__
die eine Instanz der Decorator-Klasse nicht haben wird?class Foo: @MyDec(...) def method(self, ...): blah
der, der nicht funktioniert, weil erFoo().method
keine gebundene Methode ist und nichtself
automatisch übergeben wird. Auch dies kann behoben werden, indemMyDec
ein Deskriptor erstellt und gebundene Methoden erstellt werden. Dies ist jedoch aufwändiger__get__
und viel weniger offensichtlich. Am Ende sind Dekorateurklassen nicht so bequem, wie sie scheinen.Verwendung des Dekorateurs
Dann ist die
produziert
aber
produziert
quelle
Dies ist eine Vorlage für einen Funktionsdekorateur, die nicht erforderlich ist,
()
wenn keine Parameter angegeben werden sollen:Ein Beispiel hierfür ist unten angegeben:
quelle
factor_or_func
(oder einen anderen Parameter) sollte nie zugewiesen wird inwrapper()
.locals()
?()
.In meinem Fall habe ich beschlossen, dies über ein einzeiliges Lambda zu lösen, um eine neue Dekorationsfunktion zu erstellen:
Bei der Ausführung wird Folgendes gedruckt:
Vielleicht nicht so erweiterbar wie andere Lösungen, hat aber für mich funktioniert.
quelle
Das Schreiben eines Dekorators, der mit und ohne Parameter arbeitet, ist eine Herausforderung, da Python in diesen beiden Fällen ein völlig anderes Verhalten erwartet! Viele Antworten haben versucht, dies zu umgehen, und im Folgenden finden Sie eine Verbesserung der Antwort von @ norok2. Insbesondere eliminiert diese Variation die Verwendung von
locals()
.Nach dem gleichen Beispiel wie bei @ norok2:
Spielen Sie mit diesem Code .
Der Haken ist, dass der Benutzer Schlüssel- und Wertepaare von Parametern anstelle von Positionsparametern angeben muss und der erste Parameter reserviert ist.
quelle
Es ist bekannt, dass die folgenden zwei Codeteile nahezu gleichwertig sind:
Ein häufiger Fehler ist zu denken, dass
@
das Argument ganz links einfach verborgen bleibt .Es wäre viel einfacher, Dekorateure zu schreiben, wenn das oben Genannte so
@
funktioniert. Leider wird das nicht so gemacht.Wait
Stellen Sie sich einen Dekorateur vor, der die Programmausführung für einige Sekunden übernimmt. Wenn Sie keine Wartezeit einhalten, beträgt der Standardwert 1 Sekunde. Anwendungsfälle sind unten aufgeführt.Wenn
Wait
ein Argument wie z. B. vorhanden ist@Wait(3)
, wird der Aufruf zuvorWait(3)
ausgeführt etwas anderes passiert.Das heißt, die folgenden zwei Codeteile sind äquivalent
Das ist ein Problem.
Eine Lösung ist unten gezeigt:
Beginnen wir mit der Erstellung der folgenden Klasse
DelayedDecorator
:Jetzt können wir Dinge schreiben wie:
Beachten Sie, dass:
dec
akzeptiert nicht mehrere Argumente.dec
akzeptiert nur die zu verpackende Funktion.import inspect class PolyArgDecoratorMeta (Typ): def call (Wait, * args, ** kwargs): try: arg_count = len (args) if (arg_count == 1): if callable (args [0]): SuperClass = inspect. getmro (PolyArgDecoratorMeta) [1] r = SuperClass. Anruf (Wait, args [0]) else: r = DelayedDecorator (Wait, * args, ** kwargs) else: r = DelayedDecorator (Wait, * args, ** kwargs) endlich: pass return r
Zeitklasse importieren Warten (metaclass = PolyArgDecoratorMeta): def init (i, func, delay = 2): i._func = func i._delay = delay
Die folgenden zwei Codeteile sind äquivalent:
Wir können
"something"
sehr langsam wie folgt auf die Konsole drucken :Schlussbemerkungen
Es mag wie eine Menge Code aussehen, aber Sie müssen nicht die Klassen schreiben
DelayedDecorator
undPolyArgDecoratorMeta
jede Zeit. Der einzige Code, den Sie persönlich schreiben müssen, ist ziemlich kurz:quelle
Definieren Sie diese "Dekorationsfunktion", um eine benutzerdefinierte Dekorationsfunktion zu generieren:
benutze es so:
quelle
Tolle Antworten oben. Dies zeigt auch
@wraps
, wie die Dokumentzeichenfolge und der Funktionsname von der ursprünglichen Funktion übernommen und auf die neue umschlossene Version angewendet werden:Drucke:
quelle
Falls sowohl die Funktion als auch der Dekorateur Argumente annehmen müssen, können Sie den folgenden Ansatz verfolgen.
Zum Beispiel gibt es einen Dekorateur namens,
decorator1
der ein Argument akzeptiertWenn das
decorator1
Argument nun dynamisch sein oder beim Aufrufen der Funktion übergeben werden muss,Im obigen Code
seconds
ist das Argument fürdecorator1
a, b
sind die Argumente vonfunc1
quelle