Generator-Wiederherstellung mit Decorator

8

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):

%Vor%

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.

    
Vyktor 30.10.2014, 14:30
quelle

2 Antworten

6

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:

%Vor%

Sie können den Decorator auch mit Generator- und Nichtgeneratorfunktionen arbeiten, indem Sie inspect um festzustellen, ob Sie einen Generator dekorieren:

%Vor%

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.

    
dano 30.10.2014, 15:25
quelle
3
  

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) .

    
x3al 30.10.2014 14:43
quelle

Tags und Links