Der beste Weg, den Rückgabewert von einem Python-Generator zu erhalten

8

Seit Python 3.3, wenn eine Generatorfunktion einen Wert zurückgibt, wird dies der Wert für die StopIteration-Ausnahme, die ausgelöst wird. Dies kann auf verschiedene Arten gesammelt werden:

  • Der Wert eines yield from -Ausdrucks, der die umschließende Funktion impliziert, ist ebenfalls ein Generator.
  • Einen Aufruf an next() oder .send() in einem try / except-Block abwickeln.

Wenn ich jedoch einfach den Generator in einer for-Schleife durchlaufen möchte - der einfachste Weg -, scheint es keine Möglichkeit zu geben, den Wert der StopIteration-Ausnahme und somit den Rückgabewert zu sammeln. Ich verwende ein einfaches Beispiel, in dem der Generator Werte liefert, und gibt am Ende eine Zusammenfassung zurück (laufende Summen, Durchschnittswerte, Zeitstatistiken usw.).

%Vor%

Ein Weg ist, die Schleife selbst zu handhaben:

%Vor%

Aber das wirft die Einfachheit der for-Schleife weg. Ich kann yield from nicht verwenden, da dies erfordert, dass der aufrufende Code selbst ein Generator ist. Gibt es einen einfacheren Weg als die oben gezeigte Roll-Ones-for-Schleife?

Zusammenfassung der Antworten

Kombiniert man die Antworten von @Chad S. und @KT, scheint das einfachste meine Generatorfunktion in eine Klasse umzuwandeln, die das Iteratorprotokoll verwendet:

%Vor%

Und @ Ferdinand Beyers Antwort ist am einfachsten, wenn ich den Wertproduzenten nicht umgestalten kann.

    
Chris Cogdon 03.12.2015, 18:19
quelle

4 Antworten

7

Sie können sich das value -Attribut von StopIteration (und möglicherweise StopIteration selbst) als Implementierungsdetails vorstellen, das nicht für die Verwendung in "normalem" Code ausgelegt ist.

Schauen Sie sich PEP 380 an Das gibt das yield from -Feature von Python 3.3 an: Es wird diskutiert, dass einige Alternativen zur Verwendung von StopIteration , um den Rückgabewert zu übernehmen, berücksichtigt werden.

Da Sie den Rückgabewert in einer normalen for -Schleife nicht erhalten sollen, gibt es keine Syntax dafür. Genauso wie Sie das StopIteration nicht explizit abfangen sollen.

Eine nette Lösung für Ihre Situation wäre eine kleine Utility-Klasse (möglicherweise nützlich genug für die Standardbibliothek):

%Vor%

Dies umschließt einen beliebigen Generator und fängt seinen Rückgabewert ein, um später untersucht zu werden:

%Vor%     
Ferdinand Beyer 03.12.2015, 18:30
quelle
6

Sie könnten einen Helfer-Wrapper erstellen, der die StopIteration abfängt und den Wert für Sie extrahiert:

%Vor%     
KT. 03.12.2015 18:44
quelle
3

Die offensichtlichste Methode, die ich mir dafür vorstellen kann, wäre ein benutzerdefinierter Typ, der sich die Zusammenfassung für Sie merken würde.

%Vor%     
Chad S. 03.12.2015 18:38
quelle
0

Ein einfacher Weg, den Rückgabewert zu handhaben (einer, der keine Hilfsklasse instanziiert), ist die Verwendung der Abhängigkeitsinjektion .

Das heißt, man kann die Funktion übergeben, um den Rückgabewert mit der folgenden Wrapper / Helfer-Generator-Funktion zu bearbeiten / zu bearbeiten:

%Vor%

Zum Beispiel das folgende -

%Vor%

führt zu -

%Vor%     
cjerdonek 26.01.2017 14:32
quelle

Tags und Links