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

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

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

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


当前回答

这个函数用来写协程

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

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

其他回答

这个函数用来写协程

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

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

send方法实现协程。

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

itr.send(None)和next(itr)是一样的你所做的是在生成器中给出yield给出的值。

下面的例子清楚地说明了这一点,以及如何更实际地使用它。

def iterator_towards(dest=100):
    value = 0
    while True:
        n = yield value
        if n is not None:
            dest = n
        if dest > value:
            value += 1
        elif dest < value:
            value -= 1
        else:
            return

num = iterator_towards()
for i in num:
    print(i)
    if i == 5:
        num.send(0)

这将打印:

0
1
2
3
4
5
3
2
1
0

i == 5处的代码告诉它发送0。这不是iterator_toward中的None,所以它改变了dest的值,然后我们迭代到0。

但是请注意,在值5之后没有值4。这是因为.send(0)的性质是它被输出值为4,而不输出。

如果我们添加一个continue,我们可以重新得到相同的值。

def iterator_towards(dest=100):
    value = 0
    while True:
        n = yield value
        if n is not None:
            dest = n
            continue
        if dest > value:
            value += 1
        elif dest < value:
            value -= 1
        else:
            return

这将允许您迭代一个列表,但也动态地发送它的新目标值。

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

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()方法控制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(),则结果将是传递给该方法的值。