Python 为什么 next 会引发 'StopIteration',而 'for' 会正常返回?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14413969/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:22:31  来源:igfitidea点击:

Why does next raise a 'StopIteration', but 'for' do a normal return?

pythoniteratorgeneratorstopiteration

提问by

In this piece of code, why does using forresult in no StopIterationor is the forloop trapping all exceptions and then silently exiting? In which case, why do we have the extraneous return?? Or is the raise StopIterationcaused by: return None?

在这段代码中,为什么 usingfor结果为 noStopIteration或者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)

Assuming StopIterationis being triggered by: return None. When is GeneratorExitgenerated?

假设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)

If I manually do a:

如果我手动执行:

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

In which case why don't I see a traceback?

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

采纳答案by Martijn Pieters

The forloop listens for StopIterationexplicitly.

for循环监听StopIteration明确。

The purpose of the forstatement is to loop over the sequence provided by an iterator and the exception is used to signal that the iterator is now done; fordoesn't catch other exceptions raised by the object being iterated over, just that one.

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

That's because StopIterationis the normal, expected signal to tell whomever is iterating that there is nothing more to be produced.

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

A generator function is a special kind of iterator; it indeed raises StopIterationwhen the function is done (i.e. when it returns, so yes, return Noneraises StopIteration). It is a requirement of iterators; they mustraise StopIterationwhen they are done; in fact, once a StopIterationhas been raised, attempting to get another element from them (through next(), or calling the .next()(py 2) or .__next__()(py 3) method on the iterator) mustalways raise StopIterationagain.

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

GeneratorExitis an exception to communicate in the otherdirection. You are explicitly closinga generator with a yieldexpression, and the way Python communicates that closure to the generator is by raising GeneratorExitinside of that function. You explicitly catch that exception inside of countdown, its purpose is to let a generator clean up resources as needed when closing.

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

A GeneratorExitis not propagated to the caller; see the generator.close()documentation.

AGeneratorExit不会传播给调用者;请参阅generator.close()文档