我理解让步。但是生成器的send函数是做什么的呢?文件说:
generator.send(值)
恢复执行并向生成器函数“发送”一个值。value参数变成当前yield表达式的结果。send()方法返回生成器产生的下一个值,如果生成器退出而没有产生另一个值,则引发StopIteration。
这是什么意思?我以为value是生成器函数的输入?短语“send()方法返回生成器产生的下一个值”似乎也是yield的确切目的,它也返回生成器产生的下一个值。
有没有一个生成器利用send完成了yield不能完成的事情的例子?
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!"