【问题标题】:Why does this Python generator/coroutine lose a value? [duplicate]为什么这个 Python 生成器/协程会丢失一个值? [复制]
【发布时间】:2017-12-24 06:06:01
【问题描述】:

阅读 Python 协程时,我遇到了这段代码:

def countdown(n):
    print("Start from {}".format(n))
    while n >= 0:
        print("Yielding {}".format(n))
        newv = yield n
        if newv is not None:
            n = newv
        else:
            n -= 1

c = countdown(5)
for n in c:
    print(n)
    if n == 5: c.send(2)

奇怪的输出:

Start from 5
Yielding 5
5
Yielding 3
Yielding 2
2
Yielding 1
1
Yielding 0
0

特别是,它错过了打印3。为什么?


引用的问题没有回答这个问题,因为我没有问send 做了什么。它将值发送回函数。我要问的是为什么在我发出send(3) 之后,下一个产量应该是 3,而不是导致 for 循环打印 3。

【问题讨论】:

  • 首先,它也错过了 4。其次,你认为c.send(3) 是做什么的?
  • @alfasin 因为c.send(3),它错过了4。关键是代码应该将n 设置为3,然后在下一个循环中,产生3。但它没有被打印出来。为什么?
  • if newv is not None: 块中添加print('newv: {}'.format(newv) 会更清晰

标签: python generator coroutine


【解决方案1】:

您从未检查过c.send(3) 调用的返回值。 事实上,send 方法本身似乎推进了生成器, 所以你失踪的3 在那个c.send(3) 电话中是yielded。

def countdown(n):
    while n >= 0:
        newv = yield n
        if newv is not None:
            n = newv
        else:
            n -= 1

c = countdown(5)
print(next(c))  
print(c.send(3))
print(next(c))  

输出将是:

5
3
2

其实是documented:

generator.send(值)

恢复执行并将一个值“发送”到生成器函数中。 value 参数成为当前 yield 表达式的结果。 send() 方法返回生成器产生的下一个值,或者 如果生成器退出而没有产生另一个,则引发 StopIteration 价值。

【讨论】:

    【解决方案2】:

    你在c.send() 中失败了。您在 n==5 时进行比较,但您没有发送 5(在您的函数中为 n-1),您发送的是 3。例如,它不打印 4。

    尝试相同的代码,但使用c.send(5),它将从 5 打印到 0。

    c = countdown(5)
    for n in c:
        print(n)
        if n == 5: c.send(5)
    

    【讨论】:

    • 实际上,它不是从 5 打印到 0。它打印 53210,缺少4。同样的问题。
    猜你喜欢
    • 2013-08-02
    • 2014-09-11
    • 2020-06-05
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    • 2019-05-04
    • 1970-01-01
    • 2017-02-11
    相关资源
    最近更新 更多