首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python链式` `yield `

Python链式` `yield `
EN

Stack Overflow用户
提问于 2018-12-07 05:13:26
回答 1查看 381关注 0票数 0

我在阅读这篇关于python中的async和await的article时,看到了以下示例代码:

代码语言:javascript
复制
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)已经在下面的实验中耗尽了生成器?

代码语言:javascript
复制
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

有没有人能解释一下?

附言:这不是一个经过深思熟虑的标题,请帮我修改一下……

EN

回答 1

Stack Overflow用户

发布于 2018-12-07 06:58:50

正如@Steven Rumbalski已经在评论中解释的那样:生成器只产生一个值- 42。在第二次调用中,迭代器引发被except __StopIteration__ as exc:捕获的StopIteration。所以你是完全正确的,因为初始的next(gen)已经耗尽了生成器。在您的第二个示例中也是如此,但是在本例中您没有捕获到StopIteration异常。为了进一步阅读,我将引用PEP380 --委派给子生成器的语法。

为生成器迭代器添加了一个新的send()方法,该方法恢复生成器并发送一个值,该值将成为当前yield expression表达式的结果。send()方法返回生成器生成的下一个值,或者如果生成器退出而没有生成其他值,则引发StopIteration

来自PEP342

那么,为什么你在gen.send(value * 2)上又能得到84呢?此时,value的值仍然是上一次调用value = next(gen)时的42。所以你只是得到了你想要发送给迭代器的84。为什么会这样呢?

考虑以下简化的示例,以便更好地理解该定义的含义。首先,我们只产生一个值。没有退货。这将导致具有value属性None的空StopIteration

代码语言:javascript
复制
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,因此StopIterationvalue属性为2。

代码语言:javascript
复制
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'.

现在我们return (yield 1)。根据PEP342的规则,作为gen.send(3)的值的3将成为当前屈服表达式的结果。但是,由于生成器已经耗尽,因此会引发StopIteration异常。这导致3作为提升的StopIterationvalue

代码语言:javascript
复制
def generator():
    return (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 '3'.
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53659759

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档