2013-01-06 3 views
21

Ich bin neugierig auf den Unterschied zwischen raise StopIteration und return Anweisung in Generatoren.Was ist der Unterschied zwischen Raise StopIteration und einer Return-Anweisung in Generatoren?

Gibt es zum Beispiel einen Unterschied zwischen diesen beiden Funktionen?

def my_generator0(n): 
    for i in range(n): 
     yield i 
     if i >= 5: 
      return 

def my_generator1(n): 
    for i in range(n): 
     yield i 
     if i >= 5: 
      raise StopIteration 

ich das mehr „pythonic“ Art und Weise zu raten, es zu tun ist der zweite Weg (bitte korrigieren Sie mich, wenn ich falsch), aber soweit ich beide Wege werfen eine StopIteration Ausnahme sehen.

+2

expliziter oder impliziter ('off' Ende) 'return' ist die vorgesehene Weise einen Generator zu beenden. Wenn PEP 479 akzeptiert wird, wird die 'raise StopIteration' Version eventuell nicht mehr so ​​funktionieren wie jetzt. –

Antwort

28

Es ist nicht notwendig, StopIteration explizit zu erhöhen, denn das ist, was eine bare return Anweisung für eine Generatorfunktion tut - also ja, sie sind die gleichen. Aber nein, nur mit return ist mehr Pythonic.

Von: http://docs.python.org/2/reference/simple_stmts.html#the-return-statement (gültig bis Python 3,2)

In einer Generatorfunktion wird die return-Anweisung keine expression_list aufzunehmen erlaubt. In diesem Zusammenhang zeigt eine leere Rückgabe an, dass der Generator fertig ist und die StopIteration ausgelöst wird.

Oder wie @Bakuriu weist darauf hin - die Semantik von Generatoren hat etwas für Python 3.3, so dass die folgende ist besser geeignet geändert:

In einer Generatorfunktion, die return-Anweisung gibt an, dass der Generator fertig und führt dazu, dass StopIteration ausgelöst wird. Der zurückgegebene Wert (falls vorhanden) wird als Argument zum Erstellen von StopIteration verwendet und wird zum StopIteration.value-Attribut.

+3

In Python3 kann die Rückgabe ein Ausdruck-Liste-Argument haben: http://docs.python.org/3.3/reference/simple_stmts.html#the-return-statement – Bakuriu

3

Das stimmt, sie sind äquivalent, außer dass das eine lesbar ist, während das andere obskur ist. Dies stammt aus der allerersten Version von Generatoren (PEP 255, unter "Specification: Return"), und die nachfolgenden Erweiterungen von (zB Coroutinen) ändern dies nicht. 3.3's yield from (PEP 380) erweitert das auf return <expr> als syntaktischer Zucker für raise StopIteration(<expr>), aber das ändert nicht die Bedeutung von return;.

12

Seit Ende 2014 ist return korrekt und raise StopIteration zum Beenden eines Generators ist auf einem Abschreibungsplan. Vollständige Details finden Sie unter PEP 479.

Zusammenfassung

Dieser PEP schlägt eine Änderung an Generatoren: wenn StopIteration innerhalb eines Generators erhöht wird, es mit RuntimeError ersetzt wird. (Genauer gesagt geschieht dies, wenn die Ausnahme fast aus dem Stack-Rahmen des Generators herausspringt.) Da die Änderung rückwärtskompatibel ist, wird das Feature zunächst mit einer __future__-Anweisung eingeführt.

Acceptance

Dieser PEP durch den BDFL vom 22. November ...

Rationale

Die Wechselwirkung von Generatoren und StopIteration ist derzeit etwas überraschend und kann obskuren Fehler akzeptiert wurde verbergen.Eine unerwartete Ausnahme sollte nicht zu einem geringfügig veränderten Verhalten führen, sondern zu einem verrauschten und leicht zu debuggenden Traceback führen. Derzeit wird StopIteration, die versehentlich innerhalb einer Generatorfunktion ausgelöst wird, als das Ende der Iteration durch das Schleifenkonstrukt interpretiert, das den Generator antreibt.

...