我理解让步。但是生成器的send函数是做什么的呢?文件说:

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

这是什么意思?我以为value是生成器函数的输入?短语“send()方法返回生成器产生的下一个值”似乎也是yield的确切目的,它也返回生成器产生的下一个值。

有没有一个生成器利用send完成了yield不能完成的事情的例子?


当前回答

send方法实现协程。

如果你没有遇到过协程,你很难理解它们,因为它们改变了程序的运行方式。你可以阅读一篇好的教程了解更多细节。

其他回答

send()方法控制yield表达式左边的值。

为了理解yield的不同之处以及它所代表的值,让我们首先快速刷新python代码被求值的顺序。

第6.15节评估命令

Python从左到右计算表达式。注意,在计算赋值时,右边的值比左边的值先计算。

所以表达式a = b首先求右边的值。

如下所示,a[p('left')] = p('right')首先计算右边的值。

>>> def p(side):
...     print(side)
...     return 0
... 
>>> a[p('left')] = p('right')
right
left
>>> 
>>> 
>>> [p('left'), p('right')]
left
right
[0, 0]

收益率是做什么的?, yield将暂停函数的执行并返回给调用者,并在暂停之前停止的同一位置恢复执行。

死刑到底在哪里暂缓执行?你可能已经猜到了…… 在yield表达式的左右之间暂停执行。因此new_val = yield old_val执行在=号处停止,并且右边的值(挂起之前,也是返回给调用者的值)可能与左边的值(恢复执行后分配的值)不同。

Yield产生两个值,一个在右边,另一个在左边。

如何控制yield表达式左边的值?通过.send()方法。

6.2.9. 产量表达式

恢复后的yield表达式的值取决于恢复执行的方法。如果使用__next__()(通常通过for或next()内置函数),则结果为None。否则,如果使用send(),则结果将是传递给该方法的值。

这个函数用来写协程

def coroutine():
    for i in range(1, 10):
        print("From generator {}".format((yield i)))
c = coroutine()
c.send(None)
try:
    while True:
        print("From user {}".format(c.send(1)))
except StopIteration: pass

打印

From generator 1
From user 2
From generator 1
From user 3
From generator 1
From user 4
...

看到控件是如何来回传递的了吗?这些是协程。它们可以用于各种很酷的事情,如异步IO和类似的。

想象一下,有一个发电机,没有发送器,这是一条单行道

==========       yield      ========
Generator |   ------------> | User |
==========                  ========

但是有了send,它就变成了双向的

==========       yield       ========
Generator |   ------------>  | User |
==========    <------------  ========
                  send

这为用户打开了一扇门,用户可以动态地定制生成器的行为和生成器对用户的响应。

这可能会对某些人有所帮助。这是一个不受发送函数影响的生成器。它在实例化时接受number参数,不受send的影响:

>>> def double_number(number):
...     while True:
...         number *=2 
...         yield number
... 
>>> c = double_number(4)
>>> c.send(None)
8
>>> c.next()
16
>>> c.next()
32
>>> c.send(8)
64
>>> c.send(8)
128
>>> c.send(8)
256

下面是你如何使用send来执行相同类型的函数,所以在每次迭代中你都可以改变number的值:

def double_number(number):
    while True:
        number *= 2
        number = yield number

下面是它的样子,你可以看到为number发送一个新值会改变结果:

>>> def double_number(number):
...     while True:
...         number *= 2
...         number = yield number
...
>>> c = double_number(4)
>>> 
>>> c.send(None)
8
>>> c.send(5) #10
10
>>> c.send(1500) #3000
3000
>>> c.send(3) #6
6

你也可以在for循环中这样写:

for x in range(10):
    n = c.send(n)
    print n

要获得更多帮助,请查看这个很棒的教程。

这些也让我很困惑。下面是我做的一个例子,当我试图建立一个以交替顺序(屈服,接受,屈服,接受)产生和接受信号的生成器时……

def echo_sound():

    thing_to_say = '<Sound of wind on cliffs>'
    while True:
        thing_to_say = (yield thing_to_say)
        thing_to_say = '...'.join([thing_to_say]+[thing_to_say[-6:]]*2)
        yield None  # This is the return value of send.

gen = echo_sound()

print 'You are lost in the wilderness, calling for help.'

print '------'
in_message = gen.next()
print 'You hear: "{}"'.format(in_message)
out_message = 'Hello!'
print 'You yell "{}"'.format(out_message)
gen.send(out_message)

print '------'
in_message = gen.next()
print 'You hear: "{}"'.format(in_message)
out_message = 'Is anybody out there?'
print 'You yell "{}"'.format(out_message)
gen.send(out_message)

print '------'
in_message = gen.next()
print 'You hear: "{}"'.format(in_message)
out_message = 'Help!'
print 'You yell "{}"'.format(out_message)
gen.send(out_message)

输出结果为:

You are lost in the wilderness, calling for help.
------
You hear: "<Sound of wind on cliffs>"
You yell "Hello!"
------
You hear: "Hello!...Hello!...Hello!"
You yell "Is anybody out there?"
------
You hear: "Is anybody out there?...there?...there?"
You yell "Help!"

send方法实现协程。

如果你没有遇到过协程,你很难理解它们,因为它们改变了程序的运行方式。你可以阅读一篇好的教程了解更多细节。