【问题标题】:list-comprehension throws a RuntimeError列表理解引发 RuntimeError
【发布时间】:2020-09-16 20:46:24
【问题描述】:

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

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?

【问题讨论】:

  • print yield 的每个参数;你会看到区别的。
  • 我无法重复这个问题,它对我有用:>>> tuple(next(it) for it in iters); (1, 3, 5)
  • @Prune 这不是重复的。我相信这是一个有效的错误,StopIteration 异常应该由生成器表达式捕获和处理,而不是作为RuntimeError 重新引发。
  • @antont 查看演示:repl.it/@blhsing/VagueFreshKernel
  • @blhsing 我现在看到了;我对代码做了更多的修改,而且....是的,你是对的。

标签: python python-3.x python-2.7 list-comprehension python-zip


【解决方案1】:

这是 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) 引发的异常。该功能的目标是使两个语句的行为相同,这就是更改影响生成器但不影响列表推导的原因。

【讨论】:

    猜你喜欢
    • 2017-10-14
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多