python - StopIteration 何时会转换为 RuntimeError?

标签 python python-3.x runtime-error generator stopiteration

我正在阅读 Python 3 的文档 here :

If a generator code directly or indirectly raises StopIteration, it is converted into a RuntimeError (retaining the StopIteration as the new exception's cause).

我不明白,谁能解释一下?

这是我在 Python 3.6 中尝试过的,但似乎没有发现任何东西:

def gen1():
    yield from [1, 2, 3]
    raise StopIteration

def gen2():
    raise StopIteration

try:
    a = list(gen1())
    # a == [1, 2, 3]
except RuntimeError:
    print("Caught")

try:
    a = gen1()
    next(a), next(a), next(a), next(a), next(a)
except RuntimeError:
    print("Caught")

try:
    gen2()
except RuntimeError:
    print("Caught")

try:
    a = list(gen2())
except RuntimeError:
    print("Caught")

特别是,对 gen2() 的两次调用都引发了 StopIteration,但仍未转换为 RuntimeError

最佳答案

您没有注意到此更改适用于 Python 3.7 及更新版本。 您不会在 Python 3.6 或更早版本中看到转换,除非您首先使用 from __future__ 导入启用该功能(自 Python 3.5 起可用)。

从您链接的同一页面:

Changed in version 3.5: Introduced the RuntimeError transformation via from __future__ import generator_stop, see PEP 479.

Changed in version 3.7: Enable PEP 479 for all code by default: a StopIteration error raised in a generator is transformed into a RuntimeError.

PEP 479 -- Change StopIteration handling inside generators进一步详细说明为何进行此更改以及如何应用。对于在 Python 3.7 上运行的代码,输出变为:

>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=7, micro=0, releaselevel='final', serial=0)
>>> def gen1():
...     yield from [1, 2, 3]
...     raise StopIteration
...
>>> def gen2():
...     yield 42  # make this an actual generator
...     raise StopIteration
...
>>> try:
...     a = list(gen1())
... except RuntimeError:
...     print("Caught")
...
Caught
>>> try:
...     a = gen1()
...     next(a), next(a), next(a), next(a), next(a)
... except RuntimeError:
...     print("Caught")
...
Caught
>>> try:
...     a = list(gen2())
... except RuntimeError:
...     print("Caught")
...
Caught

请注意,我向 gen2() 添加了 yield 42 行以使其成为生成器。如果主体中没有 yieldyield from,您将获得一个常规函数。调用一个生成器函数会产生一个生成器对象并且函数主体开始暂停,而调用一个普通函数会立即执行主体:

>>> def normal():
...     raise StopIteration
...
>>> def generator():
...     raise StopIteration
...     yield  # never reached, but this is now a generator
...
>>> normal()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in normal
StopIteration
>>> generator()
<generator object generator at 0x105831ed0>
>>> next(generator())
Traceback (most recent call last):
  File "<stdin>", line 2, in generator
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: generator raised StopIteration

对于 Python 3.6,您将使用 from __future__ import generator_stop 编译器开关(在编写脚本或模块时在代码顶部使用它):

>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=6, micro=5, releaselevel='final', serial=0)
>>> def generator():
...     raise StopIteration
...     yield
...
>>> next(generator())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in generator
StopIteration
>>> from __future__ import generator_stop
>>> def generator():  # re-define it so it is compiled anew
...     raise StopIteration
...     yield
...
>>> next(generator())
Traceback (most recent call last):
  File "<stdin>", line 2, in generator
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: generator raised StopIteration

关于python - StopIteration 何时会转换为 RuntimeError?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51712065/

相关文章:

python - 使用 xpath 获取文章文本但省略一些标签

python - 如何存储 itertools.chain 并多次使用它?

python - 时间序列月平均值 - 想要在月中绘制平均值;目前已到最后

logging - Go:文件错误记录中的新行

python - 使用 Facebook Prophet 在具有多个时间序列的数据框中进行时间序列预测

python - 如何在 Py2 和 Py3 上将带有 unicode 数据的行转换为 latin-1 编码的 csv 数据?

Visual Studio Code 中的 Python3 Linting

python - 不包括前导零的随机数的排列

php - ZF2 - 运行时异常 : Module (ZfcUserDoctrineORM) could not be initialized

ios-simulator - IOS 8 模拟器无法启动