Lassen Sie uns eine Klasse haben, deren Funktion von Zeit zu Zeit fehlschlägt, aber nach einigen Aktionen funktioniert sie einfach perfekt.
Ein Beispiel für ein echtes Leben wäre Mysql Query, das _mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')
erhöht, aber nach der Client-Wiederherstellung funktioniert es gut.
Ich habe versucht, Decorator dafür zu schreiben:
%Vor%Und wenn der Client die Verbindung verliert, wird er einfach wieder verbunden und alle sind glücklich.
Aber was, wenn ich get_data()
in Generator umwandeln möchte (und yield
Anweisung verwenden):
Nun, das vorherige Beispiel funktioniert nicht, weil die innere Funktion bereits den Generator zurückgegeben hat und nach dem ersten Aufruf von next()
abgebrochen wird.
Wie ich es verstehe, wenn Python sieht yield
Inside-Methode gibt es nur Kontrolle sofort ( ohne eine einzige Anweisung ) und wartet auf die erste next()
.
Ich habe es geschafft, indem es ersetzt:
%Vor%Mit:
%Vor% Aber ich bin neugierig, ob es elegantere (pythischere) Wege gibt, dies zu tun. Gibt es eine Möglichkeit, Python dazu zu bringen, den gesamten Code bis zum ersten yield
auszuführen und dann zu warten?
Ich bin mir der Möglichkeit bewusst, nur return tuple(func(self, *args, **kwargs))
aufzurufen, aber ich möchte vermeiden, dass alle Datensätze gleichzeitig geladen werden.
Zunächst denke ich, dass die Lösung, die Sie gerade verwenden, in Ordnung ist. Wenn Sie einen Generator dekorieren, muss sich der Dekorator mindestens wie ein Iterator über diesem Generator verhalten. Das zu tun, indem man den Dekorator zu einem Generator macht, ist vollkommen in Ordnung. Wie x3al sagte, ist die Verwendung von yield from func(...)
anstelle von for row in func(...): yield row
eine mögliche Optimierung.
Wenn Sie auch vermeiden möchten, dass der Decorator tatsächlich zu einem Generator wird, können Sie dies tun, indem Sie next
verwenden, das bis zum ersten yield
ausgeführt wird, und den ersten ausgegebenen Wert zurückgeben. Sie müssen den Decorator dazu bringen, diesen ersten Wert zu erfassen und zurückzugeben, zusätzlich zu den restlichen Werten, die vom Generator geliefert werden. Sie könnten das mit itertools.chain
tun:
Sie können den Decorator auch mit Generator- und Nichtgeneratorfunktionen arbeiten, indem Sie inspect
um festzustellen, ob Sie einen Generator dekorieren:
Ich würde die yield
/ yield from
-basierte Lösung bevorzugen, es sei denn, Sie müssen zusätzlich zu Generatoren auch reguläre Funktionen einrichten.
Gibt es eine Möglichkeit, Python dazu zu bringen, den gesamten Code bis zur ersten Ausgabe auszuführen und dann zu warten?
Ja und es heißt next(your_generator)
. Rufen Sie next()
einmal auf und der Code wartet genau nach dem ersten yield
. Sie können ein weiteres yield
vor der Schleife platzieren, wenn Sie den ersten Wert nicht verlieren möchten.
Wenn Sie Python 3.3+ verwenden, können Sie auch
ersetzen %Vor% mit yield from func(self, *args, **kwargs)
.
Tags und Links python decorator python-3.x yield