45

我很好奇生成器中使用raise StopIterationreturn语句之间的区别。

例如,这两个功能之间有什么区别吗?

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

我猜测更“pythonic”的方式是第二种方式(如果我错了,请纠正我),但据我所知,两种方式都会引发StopIteration异常。

4

3 回答 3

52

没有必要明确地 raise StopIteration,因为这是一个简单的return语句对生成器函数所做的 - 所以是的,它们是相同的。但不,只是使用return更 Pythonic。

来自: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 属性。

于 2013-01-06T15:56:44.023 回答
24

截至 2014 年底return是正确的,并且raise StopIteration对于终止发电机是在折旧计划中。详情请参阅PEP 479

抽象的

此 PEP 建议对生成器进行更改:当StopIteration在生成器中引发时,将其替换为RuntimeError. (更准确地说,这发生在异常即将从生成器的堆栈帧中冒出时。)因为更改是向后不兼容的,所以该功能最初是使用__future__语句引入的。

验收

该 PEP 于 11 月 22 日被 BDFL 接受……</p>

基本原理

生成器和 StopIteration 的交互目前有点令人惊讶,并且可以隐藏晦涩的错误。意外的异常不应导致行为的细微改变,而应引起嘈杂且易于调试的回溯。目前,在生成器函数中意外引发的 StopIteration 将被驱动生成器的循环构造解释为迭代的结束。

…</p>

于 2015-05-13T14:23:40.743 回答
5

没错,它们是等价的,除了一个是可读的而另一个是晦涩的。这可以追溯到生成器的第一个版本(PEP 255,在“规范:返回”下),随后的增强(例如协程)并没有改变这一点。3.3 yield from(PEP 380) 将其扩展return <expr>为 的语法糖raise StopIteration(<expr>),但这并没有改变 . 的含义return;

于 2013-01-06T16:00:16.687 回答