为什么下一个为什么会引发“ StopIteration”,而“ for”却会正常返回?


72

在这段代码中,为什么使用for结果为noStopIterationfor循环捕获所有异常然后静默退出?在这种情况下,为什么会有多余的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 None。什么时候GeneratorExit产生的?

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??

在这种情况下,为什么看不到追溯?

Answers:


96

for循环监听StopIteration明确。

for语句的目的是循环遍历迭代器提供的序列,并使用异常表示当前迭代器已完成。for不会捕获被迭代的对象引发的其他异常,只是那个异常。

这是因为这StopIteration是正常的,预期的信号,用于告诉任何正在迭代的人不再生产更多东西。

生成器函数是一种特殊的迭代器。StopIteration当函数完成时,它确实会上升(即,当它返回时,所以return None会上升StopIteration)。这是迭代器的要求;他们必须StopIteration在完成时加薪;实际上,一旦StopIteration引发了a,尝试从它们中获取另一个元素(通过next(),或在迭代器上调用.next()(py 2)或.__next__()(py 3)方法)必须总是StopIteration再次引发。

GeneratorExit另一个方向上交流是一个例外。您正在使用表达式显式关闭生成器,yieldPython将闭包传递给生成器的方式是通过引发GeneratorExit该函数的内部。您可以在中明确捕获该异常countdown,其目的是让生成器在关闭时根据需要清除资源。

AGeneratorExit不传播给呼叫者;请参阅generator.close()文档


5
还要注意,for将仅在评估迭代器时捕获异常。如果它在for循环的主体内引发,它将无法捕获。
乔纳斯·谢弗(JonasSchäfer)2013年

1
@JonasWielicki:对句子进行了一些扩展以删除该解释。:-)
马丁·彼得
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.