【问题标题】:Why does next raise a 'StopIteration', but 'for' do a normal return?为什么 next 会引发“StopIteration”,但“for”会正常返回?
【发布时间】:2013-01-03 01:14:10
【问题描述】:

在这段代码中,为什么使用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??

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

【问题讨论】:

    标签: python iterator generator stopiteration


    【解决方案1】:

    for 循环显式侦听StopIteration

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

    这是因为StopIteration 是正常的、预期的信号,它告诉正在迭代的任何人没有更多的东西要产生。

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

    GeneratorExit 是在other 方向上通信的一个例外。您正在显式关闭带有yield 表达式的生成器,Python 将该关闭传递给生成器的方式是在该函数内部引发GeneratorExit。您在countdown 中显式捕获该异常,其目的是让生成器在关闭时根据需要清理资源。

    GeneratorExit 不会传播给调用者;见generator.close() documentation

    【讨论】:

    • StopIteration 可以通过为next() 提供默认值来避免,以防找不到匹配项,例如next(generator_expression, None)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-29
    相关资源
    最近更新 更多