这两个代码片段的区别仅在于列表的构造方式。一个使用[]
,另一个使用list()
。
这个消耗了iterable,然后引发StopIteration
:
>>> try:
... iterable = iter(range(4))
... while True:
... print([next(iterable) for _ in range(2)])
... except StopIteration:
... pass
...
[0, 1]
[2, 3]
这个消耗了iterable并循环永久打印空列表。
>>> try:
... iterable = iter(range(4))
... while True:
... print(list(next(iterable) for _ in range(2)))
... except StopIteration:
... pass
...
[0, 1]
[2, 3]
[]
[]
[]
etc.
此行为有哪些规则?
答案 0 :(得分:3)
请参阅PEP479,其中说明了
发电机和StopIteration的相互作用目前有所不同 令人惊讶的是,可以隐藏晦涩的错误。意外的例外 不应该导致微妙改变的行为,但应该导致一个 嘈杂且易于调试的追溯。 目前,StopIteration已经提出 意外地在发电机功能内将被解释为 循环结构驱动发生器的迭代结束。
(强调我的)
因此list
的构造函数遍历传递的生成器表达式,直到引发StopIteration
错误(通过调用next(iterable)
而没有第二个参数)。另一个例子:
def f():
raise StopIteration # explicitly
def g():
return 'g'
print(list(x() for x in (g, f, g))) # ['g']
print([x() for x in (g, f, g)]) # `f` raises StopIteration
另一方面,* comprehension在将StopIteration
传播给调用者时的工作方式不同。
链接的PEP提出的行为如下
如果
StopIteration
即将从生成器框架中冒出来,那就是 替换为RuntimeError
,这会导致next()
调用(其中) 调用生成器失败,将该异常传递出去。从那时起 就像任何旧例外一样。
Python 3.5添加了可以使用
启用的generator_stop
feature
from __future__ import generator_stop
此行为在Python 3.7中将是默认行为。