web-dev-qa-db-ja.com

次に「StopIteration」を発生させるのに、「for」は通常のリターンを行うのはなぜですか?

このコードでは、なぜforを使用してもStopIterationにならないのか、またはforループがすべての例外をトラップしてから静かに終了するのですか?その場合、なぜ余分なreturnがあるのですか??またはraise StopIteration のせいで: return None

#!/usr/bin/python3.1
def countdown(n):
    print("counting down")
    while n >= 9:
        yield n
        n -= 1
    return

for x in countdown(10):
    print(x)

c = countdown(10)
next(c)
next(c)
next(c)

StopIterationが以下によってトリガーされていると仮定します:return NoneGeneratorExitはいつ生成されますか?

def countdown(n):
    print("Counting down from %d" % n)
    try:
        while n > 0:
            yield n
            n = n - 1
    except GeneratorExit:
        print("Only made it to %d" % n)

私が手動で行う場合:

c = countdown(10)
c.close() #generates GeneratorExit??

どの場合、トレースバックが表示されないのですか?

55
user621819

forループは、StopIterationを明示的にリッスンします。

forステートメントの目的は、イテレーターによって提供されるシーケンスをループすることであり、例外はイテレーターが終了したことを示すために使用されます。 forは、反復されるオブジェクトによって発生した他の例外をキャッチしません。

これは、StopIterationが、生成されるものがこれ以上ないことを反復している人に知らせるための通常の予想される信号だからです。

ジェネレーター関数は特別な種類のイテレーターです。関数が完了すると、実際にStopIterationが発生します(つまり、戻るときに、そう、はい、_return None_はStopIterationを発生させます)。反復子の要件です。それらはmust終了したらStopIterationを上げます;実際、StopIterationが発生すると、それらから別の要素を取得しようとする(next()を介して、または.next()(py 2)または.__next__()(py 3)イテレータのメソッド)mustは常にStopIterationを再度発生させます。

GeneratorExitは、other方向で通信する例外です。明示的にclosingyield式を持つジェネレーターであり、方法Pythonはそのクロージャーを通信しますジェネレーターは、その関数内でGeneratorExitを上げることにより、countdown内で明示的に例外をキャッチします。

GeneratorExitは呼び出し元に伝播されません。 generator.close() documentation を参照してください。

75
Martijn Pieters