为什么嵌套的空生成器提前退出而不会引发错误?

时间:2018-03-06 17:30:40

标签: python python-3.x generator

我面临着嵌套generators的奇怪行为。

def empty_generator():
    for i in []:
        yield

def gen():
    next(empty_generator())
    print("This is not printed, why?")
    yield

list(gen())  # No Error

next(empty_generator())  # Error

我希望gen()函数引发错误,因为我在空发生器周围调用next()。但事实并非如此,这些功能无处不在,无需提升或打印任何东西。

这似乎违反了最不惊讶的原则,不是吗?

2 个答案:

答案 0 :(得分:2)

从技术上讲,你没有错误;你有一个未被捕获的StopIteration异常,它用于流量控制。对list的调用(以任意可迭代为参数)捕获gen为您引发的异常。

for循环类似;每个迭代器最后都会引发StopIteration,但for循环捕获它并以响应结束。

换句话说,iterable的使用者负责捕获StopIteration。当gen调用next时,它会让异常冒泡。拨打list的电话会抓住它,但是当您明确致电next时,您就不会接听。

请注意,PEP-479会更改此行为。 Python 3.5通过__future__提供了新的语义,Python 3.6提供了弃用警告,Python 3.7(2018年夏季到期)完成了转换。我将读者引用到PEP本身以获取更多详细信息。

答案 1 :(得分:1)

一旦迭代器到达终点,它就会引发StopIteration ......停止迭代,所以list(gen())构造一个空列表。