Python链接的“收益表”

时间:2018-12-06 21:13:26

标签: python async-await

我正在阅读有关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:并不是最深思熟虑的标题,请有人帮忙解决...

1 个答案:

答案 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
相关问题