python 生成器中的代码何时停止执行?
When does the execution of the code in a python generator stop?
我试图通过构建一个行为类似于 'enumerate' 内置函数的生成器来理解 yield 语句的行为,但我发现不一致取决于我如何遍历它。
def enumerate(sequence, start=0):
n = start
for elem in sequence:
print("Before the 'yield' statement in the generator, n = {}".format(n))
yield n, elem
n += 1
print("After the 'yield' statement in the generator, n = {}".format(n))
我对生成器的理解是,一旦达到 yield 语句,代码的执行就会停止,它 returns 是一个值。这与我通过下面的脚本得到的结果相符。
a = 'foo'
b = enumerate(a)
n1,v1 = next(b)
print('n1 = {}, v1 = {}\n'.format(n1,v1))
n2,v2 = next(b)
print('n2 = {}, v2 = {}'.format(n2,v2))
在这种情况下,生成器似乎恰好在 yield 语句处停止,并在 n+=1 中使用第二个 'next' 语句恢复:
Before the 'yield' statement in the generator, n = 0
n1 = 0, v1 = f
After the 'yield' statement in the generator, n = 1
Before the 'yield' statement in the generator, n = 1
n2 = 1, v2 = o
但是,如果我使用下面的 for 循环,生成器似乎不会在 yield 语句处停止。
for n,v in enumerate(a[0:1]):
print('n = {}, v = {}'.format(n,v))
这是我得到的:
Before the 'yield' statement in the generator, n = 0
n = 0, v = f
After the 'yield' statement in the generator, n = 1
考虑评论进行编辑
我意识到我只遍历了一个元素,但我没想到会看到最后的 "After the 'yield' statement in the generator" 句子(即使我遍历所有元素也会出现。
print('\n\n')
for n,v in enumerate(a):
print('n = {}, v = {}'.format(n,v))
Before the 'yield' statement in the generator, n = 0
n = 0, v = f
After the 'yield' statement in the generator, n = 1
Before the 'yield' statement in the generator, n = 1
n = 1, v = o
After the 'yield' statement in the generator, n = 2
Before the 'yield' statement in the generator, n = 2
n = 2, v = o
After the 'yield' statement in the generator, n = 3
为什么会这样?
答案在于了解 python 中的 for 循环的作用:
它获取对象的迭代器(即 iter()
)并继续直到引发 StopIteration
异常。
StopIteration
生成器的代码完成时抛出异常,这意味着获取存在函数的 return 语句(也可以是隐式的)。
这就是为什么它不会在 yield
处停止,它会一直询问下一个 yield
,直到生成器完成。
这里的根本问题是你混淆了 你 仅通过观察就知道发电机何时会耗尽这一事实与 Python只能通过运行ning代码知道。当Python到达你认为是最后一个的yield
时,它实际上并不知道它是最后一个。如果您的生成器看起来像这样怎么办:
def enumeratex(x, start=0):
for elem in x:
yield start, x
start += 1
yield start, None
在这里,出于无人知晓的原因,在主生成器循环之后 return 编辑了最终的 None
元素。 Python 在您
之前无法知道生成器已完成
- Return 来自生成器。
- 引发错误,在这种情况下一切都会停止。
在 Python 3.7 之前的版本中,生成器可以引发 StopIteration
以指示终止。事实上,return 语句等价于 raise StopIteration
(如果 returning None
)或 raise StopIteration(return_value)
.
因此,虽然您告诉 Python 结束生成器的确切方式取决于您,但您必须明确说明。 yield
本身不会结束生成器。
TL;DR
生成器循环中的所有代码将始终 运行,即使在生成最后一个值之后也是如此,因为 Python 只能通过实际执行所有代码。
我试图通过构建一个行为类似于 'enumerate' 内置函数的生成器来理解 yield 语句的行为,但我发现不一致取决于我如何遍历它。
def enumerate(sequence, start=0):
n = start
for elem in sequence:
print("Before the 'yield' statement in the generator, n = {}".format(n))
yield n, elem
n += 1
print("After the 'yield' statement in the generator, n = {}".format(n))
我对生成器的理解是,一旦达到 yield 语句,代码的执行就会停止,它 returns 是一个值。这与我通过下面的脚本得到的结果相符。
a = 'foo'
b = enumerate(a)
n1,v1 = next(b)
print('n1 = {}, v1 = {}\n'.format(n1,v1))
n2,v2 = next(b)
print('n2 = {}, v2 = {}'.format(n2,v2))
在这种情况下,生成器似乎恰好在 yield 语句处停止,并在 n+=1 中使用第二个 'next' 语句恢复:
Before the 'yield' statement in the generator, n = 0
n1 = 0, v1 = f
After the 'yield' statement in the generator, n = 1
Before the 'yield' statement in the generator, n = 1
n2 = 1, v2 = o
但是,如果我使用下面的 for 循环,生成器似乎不会在 yield 语句处停止。
for n,v in enumerate(a[0:1]):
print('n = {}, v = {}'.format(n,v))
这是我得到的:
Before the 'yield' statement in the generator, n = 0
n = 0, v = f
After the 'yield' statement in the generator, n = 1
考虑评论进行编辑
我意识到我只遍历了一个元素,但我没想到会看到最后的 "After the 'yield' statement in the generator" 句子(即使我遍历所有元素也会出现。
print('\n\n')
for n,v in enumerate(a):
print('n = {}, v = {}'.format(n,v))
Before the 'yield' statement in the generator, n = 0
n = 0, v = f
After the 'yield' statement in the generator, n = 1
Before the 'yield' statement in the generator, n = 1
n = 1, v = o
After the 'yield' statement in the generator, n = 2
Before the 'yield' statement in the generator, n = 2
n = 2, v = o
After the 'yield' statement in the generator, n = 3
为什么会这样?
答案在于了解 python 中的 for 循环的作用:
它获取对象的迭代器(即 iter()
)并继续直到引发 StopIteration
异常。
StopIteration
生成器的代码完成时抛出异常,这意味着获取存在函数的 return 语句(也可以是隐式的)。
这就是为什么它不会在 yield
处停止,它会一直询问下一个 yield
,直到生成器完成。
这里的根本问题是你混淆了 你 仅通过观察就知道发电机何时会耗尽这一事实与 Python只能通过运行ning代码知道。当Python到达你认为是最后一个的yield
时,它实际上并不知道它是最后一个。如果您的生成器看起来像这样怎么办:
def enumeratex(x, start=0):
for elem in x:
yield start, x
start += 1
yield start, None
在这里,出于无人知晓的原因,在主生成器循环之后 return 编辑了最终的 None
元素。 Python 在您
- Return 来自生成器。
- 引发错误,在这种情况下一切都会停止。
在 Python 3.7 之前的版本中,生成器可以引发 StopIteration
以指示终止。事实上,return 语句等价于 raise StopIteration
(如果 returning None
)或 raise StopIteration(return_value)
.
因此,虽然您告诉 Python 结束生成器的确切方式取决于您,但您必须明确说明。 yield
本身不会结束生成器。
TL;DR
生成器循环中的所有代码将始终 运行,即使在生成最后一个值之后也是如此,因为 Python 只能通过实际执行所有代码。