gpt4 book ai didi

python - 生成器表达式从不引发 StopIteration

转载 作者:太空狗 更新时间:2023-10-29 17:48:37 25 4
gpt4 key购买 nike

灵感来自 my own answer ,我什至不明白它是如何工作的,请考虑以下内容:

def has22(nums):
it = iter(nums)
return any(x == 2 == next(it) for x in it)


>>> has22([2, 1, 2])
False

我希望引发 StopIteration,因为在到达 2 时,next(it) 将推进一个消耗的迭代器。然而,这种行为似乎已被完全禁用,仅适用于生成器表达式!一旦发生这种情况,生成器表达式似乎会立即中断

>>> it = iter([2, 1, 2]); any(x == 2 == next(it) for x in it)
False
>>> it = iter([2, 1, 2]); any([x == 2 == next(it) for x in it])

Traceback (most recent call last):
File "<pyshell#114>", line 1, in <module>
it = iter([2, 1, 2]); any([x == 2 == next(it) for x in it])
StopIteration
>>> def F(nums):
it = iter(nums)
for x in it:
if x == 2 == next(it): return True


>>> F([2, 1, 2])

Traceback (most recent call last):
File "<pyshell#117>", line 1, in <module>
F([2, 1, 2])
File "<pyshell#116>", line 4, in F
if x == 2 == next(it): return True
StopIteration

即使这样也行!

>>> it=iter([2, 1, 2]); list((next(it), next(it), next(it), next(it))for x in it)
[]

所以我想我的问题是,为什么要为生成器表达式启用此行为?

注意: 3.x

中的行为相同

最佳答案

开发人员认为允许这是一个错误,因为它可以掩盖隐藏的错误。因此,接受 PEP 479 意味着这将消失。

在 Python 3.5 中,如果您执行 from __future__ import generator_stop ,而在 Python 3.7 中,默认情况下,问题中的示例将失败并返回 RuntimeError 。您仍然可以使用一些 itertools 魔法实现相同的效果(允许不预先计算 nums):

from itertools import tee, islice

def has22(nums):
its = tee(nums, 2)
return any(x == y == 2 for x, y in
zip(its[0], islice(its[1], 1, None)))

它首先起作用的原因与生成器的工作方式有关。你可以想到这个 for 循环:

for a in b:
# do stuff

(大致)等同于此:

b = iter(b) 
while True:
try:
a = next(b)
except StopIteration:
break
else:
# do stuff

现在,所有示例都有 两个 for 循环嵌套在一起(一个在生成器表达式中,一个在使用它的函数中),因此当外部循环执行其 next 时,内部循环迭代一次称呼。当内部循环中的“#do stuff”为 raise StopIteration 时会发生什么?

>>> def foo(): raise StopIteration
>>> list(foo() for x in range(10))
[]

异常传播到内部循环之外,因为它不在内部循环中,并被外部 循环捕获。在新行为下,Python 将拦截即将从生成器传播出去的 StopIteration 并将其替换为 RuntimeError不会被包含的 for 循环捕获。

这也意味着这样的代码:

def a_generator():
yield 5
raise StopIteration

也会失败,并且邮件列表线程给人的印象是这无论如何都被认为是错误的形式。正确的做法是:

def a_generator():
yield 5
return

正如您所指出的,列表理解的行为已经有所不同:

>>> [foo() for x in range(10)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
File "<stdin>", line 1, in foo
StopIteration

这在某种程度上是一个实现细节泄漏 - 列表推导不会被转换为对具有等效生成器表达式的 list 的调用,显然这样做 would cause large performance penalties 的权力被认为是禁止的。

关于python - 生成器表达式从不引发 StopIteration,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16814111/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com