首页 > 解决方案 > 列表理解引发 RuntimeError

问题描述

为什么这段代码运行良好并且不抛出异常?

def myzip(*args):
    iters = [iter(arg) for arg in args]
    try:
        while True:
            yield tuple([next(it) for it in iters])
    except StopIteration:
        return


for x, y, z in myzip([1, 2], [3, 4], [5, 6]):
    print(x, y, z)

但是如果这条线

yield tuple([next(it) for it in iters])

替换为

yield tuple(next(it) for it in iters)

然后一切都停止工作并抛出一个RuntimeError

标签: pythonpython-3.xpython-2.7list-comprehensionpython-zip

解决方案


这是 Python 3.5 中引入的一个特性,而不是一个 bug。根据PEP-479,当从生成器内部引发RuntimeErrora 时,会有意重新引发StopIterationa ,这样基于生成器的迭代现在只能在生成器返回时停止,此时StopIteration会引发异常以停止迭代。

否则,在 Python 3.5 之前,StopIteration生成器中任何地方引发的异常都会停止生成器而不是传播,因此在以下情况下:

a = list(F(x) for x in xs)
a = [F(x) for x in xs]

F(x)如果在迭代过程中的某个时刻引发StopIteration异常,前者会得到截断的结果,这使得调试变得困难,而后者会传播从F(x). 该功能的目标是使两个语句的行为相同,这就是更改影响生成器但不影响列表推导的原因。


推荐阅读