ジェネレーターでのraise StopIteration
とreturn
ステートメントの違いについて知りたいです。
たとえば、これら2つの機能に違いはありますか?
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
それを行うためのより「Python的な」方法は2番目の方法だと思います(私が間違っている場合は修正してください)が、両方の方法でStopIteration
例外が発生することがわかる限り。
StopIteration
を明示的に発生させる必要はありません。これは、ジェネレータ関数に対してreturn
ステートメントを実行するだけなので、同じです。しかし、いいえ、return
を使用するだけの方がPythonicです。
From: http://docs.python.org/2/reference/simple_stmts.html#the-return-statement (Python 3.2に有効)
ジェネレーター関数では、returnステートメントにexpression_listを含めることはできません。そのコンテキストでは、ベアリターンはジェネレータが完了し、StopIterationが発生することを示します。
または、@ Bakuriuが指摘しているように、ジェネレータのセマンティクスはPython 3.3でわずかに変更されているため、以下の方が適切です。
ジェネレーター関数では、returnステートメントはジェネレーターが完了し、StopIterationが発生することを示します。戻り値(存在する場合)は、StopIterationを構築するための引数として使用され、StopIteration.value属性になります。
2014年後半の時点で、return
は正しく、発電機を終了するためのraise StopIteration
は減価償却スケジュールに従っています。詳細については PEP 479 を参照してください。
概要
このPEPは、ジェネレーターへの変更を提案しています。
StopIteration
がジェネレーター内で発生すると、RuntimeError
に置き換えられます。 (より正確には、これは、例外がジェネレーターのスタックフレームからバブリングしようとしているときに発生します。)変更は下位互換性がないため、最初に__future__
ステートメントを使用して機能が導入されます。受け入れ
このPEPは11月22日にBDFLによって承認されました…
根拠
ジェネレーターとStopIterationの相互作用は現在、いくぶん驚くべきものであり、あいまいなバグを隠すことができます。予期しない例外によって、動作が微妙に変更されることはありませんが、ノイズが多く、簡単にデバッグできるトレースバックが発生するはずです。現在、ジェネレーター関数内で偶発的に発生したStopIterationは、ジェネレーターを駆動するループ構造によって反復の終了として解釈されます。
…
それは真実です。一方は読み取り可能で、もう一方は不明瞭である点を除いて、それらは同等です。これは、最初のバージョンのジェネレーター(PEP 255、 "Specification:Return"の下)にさかのぼり、その後の(コルーチンなどの)拡張によってこれが変更されることはありません。 3.3の_yield from
_(PEP 380)は、raise StopIteration(<expr>)
の構文糖として_return <expr>
_に拡張しますが、_return;
_の意味は変わりません。