python3 生成器中的 send() 函数

python3 send() function in generators

根据docs,send()函数:

"Resumes the execution and “sends” a value into the generator function. The value argument becomes the result of the current yield expression. The send() method returns the next value yielded by the generator, or raises StopIteration if the generator exits without yielding another value. When send() is called to start the generator, it must be called with None as the argument, because there is no yield expression that could receive the value."

但我不明白,为什么 "The value argument becomes the result of the current yield expression" 没有发生在下面的例子中:

def gen():
    yield 1
    x = (yield 42)
    print(x)
    yield 2

>>>c=gen() #create generator
>>>next(c) #prints '1' and stop execution, which is caused by yield 1
>>>c.send(100) #prints '42', because 'The send() method returns the next value yielded by the generator'
>>>next(c) #prints 'None' and '2'

那么为什么 x 变量保持 'None' 尽管我通过 c.send(100) 向它发送 100? 看来,右手的 yield 表达式side 分两步工作:首先它 return 生成器调用者的值,第二个它 return 生成器内部发送函数的参数。如果在 send(42) 之前添加额外的 next(c),我将获得预期的行为并且程序会打印“100”。从文档中我不清楚为什么这两个步骤在我调用 send() 时不应该同时发生。

So why x variable stays 'None' dispite i send 100 to it by c.send(100)?

因为现在的yield不是你想的那个,是以前的那个。

当您发送 100 时,生成器仍停在 yield 1,尚未停在 yield 42,因此 100 将是 yield 1 的结果,而不是 [=14= 的结果].

为了看得更清楚,如果您修改生成器以在 z 变量中检索 yield 1 的内容,您会看到 z 确实包含 100:

>>> def gen():
...     z = yield 1
...     x = (yield 42)
...     print(x, z)
...     yield 2
... 
>>> c=gen()
>>> next(c)
1
>>> c.send(100)
42
>>> next(c)
None 100
2
>>>

这就是额外的 next() 会打印 100 的原因。返回您的代码:

def gen():
    yield 1  # first next(), stops here (before "getting out" of yield)
    x = (yield 42) # second next(), stops here (before "getting out" of yield),
                   # so, when you send(100), then 100 is given to x and execution goes on, so:
    print(x)  # 100 is printed
    yield 2  # ... and 2.

我想我已经弄明白了。

c = gen()

您在 c 变量中创建了一个生成器,其中 none 的生成器代码被执行。

next(c)

然后你用next()函数,next函数去下一个yield语句谁是yield 1这里。 所以这个 yield returns 1 并停止生成器的执行以尝试捕获一个值。

下一行是 c.send(100),所以 yield 1 正在等待一个值,而你提供了它,但这个值没有被保存。
send 方法还会执行生成器的其余部分,直到下一个 yield 语句 who is:

x = (yield 42)

所以这里的 yield return 42 并停止生成器程序以尝试捕获一个值。但在那之后你打电话

next(c)

而且您没有提供值,所以 x 现在是 None。然后执行剩下的代码(直到下一个yield语句,别忘了)

print(x)
yield 2

所以它打印 x who is None 然后 yield returns 2 并尝试捕获一个值。

试着写这个

c = gen()
next(c)
next(c)
c.send(100)

它会起作用(明白为什么!)

来自文档: value 参数成为当前 yield 表达式的结果。 send() 方法 returns 生成器产生的下一个值。

假设我们有以下无限生成器:

def infgen():
    a = 0
    while True:
        a = yield a
        a += 1

generato = infgen()

generato.send(None)

输出:0

.send(None) 的执行几乎和 next()

一样

现在我们得到 a = 0 的第一个值并且

代码在这里停止a = yield a

as value 成为当前 yield 表达式的结果

yield 表达式是 yield a。 yielded 表达式的结果是 a

generato.send(5)

.send(5) 我们将 5 发送到生成器中的 a 并继续:

yield 表达式的结果是 a = 5

一个=5

一个+=1

使用 a = 5 + 1 = 6 转到 while 循环

然后停止并产生a其中a是6

输出:6