我正在阅读有关Python中的异步和等待的article,并看到了以下示例代码:
def bottom():
# Returning the yield lets the value that goes up the call stack to come right back
# down.
return (yield 42)
def middle():
return (yield from bottom())
def top():
return (yield from middle())
# Get the generator.
gen = top()
value = next(gen)
print(value) # Prints '42'.
try:
value = gen.send(value * 2)
except StopIteration as exc:
value = exc.value
print(value) # Prints '84'.
我可以理解链接生成器以返回42
,但似乎无法绕开gen.send(value * 2)
并获得84。我本来以为最初的next(gen)
会在下面的实验中耗尽发电机的能量?
def bottom():
# Returning the yield lets the value that goes up the call stack to come right back
# down.
return (yield 42)
def middle():
return (yield from bottom())
def top():
return (yield from middle())
# Get the generator.
gen = top()
value = next(gen)
print(value) # Prints '42'.
value = next(gen)
print(value)
Traceback (most recent call last):
File "a.py", line 16, in <module>
value = next(gen)
StopIteration
有人可以解释吗?
PS:并不是最深思熟虑的标题,请有人帮忙解决...
答案 0 :(得分:0)
正如@Steven Rumbalski在评论中已经解释的那样:生成器仅生成一个值-42。在第二个调用中,迭代器将生成StopIteration
,该值由except __StopIteration__ as exc:
捕获。因此,您完全正确,因为初始next(gen)
已经耗尽了生成器。在第二个示例中也是如此,但是在这种情况下,您没有捕获StopIteration
异常。为了进一步阅读,我将引用PEP 380-委托给子生成器的语法。
为生成器迭代器添加一个新的 send()方法,该方法将恢复生成器并发送一个值,该值成为当前yield-expression的结果。 send()方法返回生成器产生的下一个值,或者如果生成器退出而不产生另一个值,则提高 StopIteration 。
来自PEP342
那么,为什么用gen.send(value * 2)
可以得到84?从上一次调用value
到现在,value = next(gen)
的值仍然是42。因此,您只需取回要发送给迭代器的84。为什么会这样?
请考虑以下简化示例,以更好地理解该定义的含义。首先,我们只产生一个值。没有退货。这将导致具有StopIteration
属性value
的空白None
。
def generator():
yield 1
gen = generator()
value = next(gen)
print(value) # Prints '1'.
try:
value = gen.send(3)
except StopIteration as exc:
value = exc.value
print(value) # Prints 'None'.
生成器中的return expr 导致从生成器退出时提升 StopIteration (expr)。
来自PEP380
然后我们return 2
在生成器之后不再产生任何值。在这种情况下,PEP380的规则开始起作用。由于返回值为2,因此value
的{{1}}属性为2。
StopIteration
现在我们def generator():
yield 1
return 2
gen = generator()
value = next(gen)
print(value) # Prints '1'.
try:
value = gen.send(3)
except StopIteration as exc:
value = exc.value
print(value) # Prints '2'.
。根据{{3}}的规则,作为return (yield 1)
的值的3成为当前yield-expression的结果。但是由于生成器已经耗尽,所以引发了gen.send(3)
异常。导致3为加注的StopIteration
的{{1}}。
value