列表推导式抛出一个运行时错误。

4
为什么这段代码可以正常运行而没有抛出异常?
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 吗?


将这些参数打印到“yield”中;你会看到区别。 - Prune
我无法重复这个问题,它在我的电脑上可以运行:>>> tuple(next(it) for it in iters); (1, 3, 5) - antont
@Prune 这不是重复的。我认为这是一个有效的错误,应该由生成器表达式捕获和处理 StopIteration 异常,而不是重新引发为 RuntimeError - blhsing
@antont 请查看演示:https://repl.it/@blhsing/VagueFreshKernel - blhsing
@blhsing 我现在明白了;我对代码进行了更多的调整,是的,你是正确的。 - Prune
好的,生成器表达式的元组是有效的,但当生成器耗尽时,它会引发StopIteration异常。有趣的是,异常没有被捕获,这似乎有些奇怪。 - antont
1个回答

5
这是Python 3.5引入的一项功能,而不是一个错误。根据PEP-479,当生成器中出现StopIteration时,RuntimeError会被有意地重新引发,以便基于生成器的迭代现在只能在生成器返回时停止,此时会引发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)引发的异常。该功能的目标是使两个语句表现相同,因此更改影响生成器但不影响列表推导式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接