使用生成器发送方法.仍然试图了解发送方法和古怪的行为

use*_*820 7 python python-2.7

这是我写的一个小函数来理解send方法:

>>> def test():
...     for x in xrange(10):
...         res = yield
...         yield res
>>> a = test()
>>> next(a)
>>> next(a)
>>> next(a)
>>> next(a)
>>> a.send(0)
Traceback (most recent call last):
   <ipython-input-220-4abef3782000> in <module>()
StopIteration
>>> a = test()
>>> a.send(0)
Traceback (most recent call last):
   <ipython-input-222-4abef3782000> in <module>()    
TypeError: can't send non-None value to a just-started generator
>>> a.send(None)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)
Run Code Online (Sandbox Code Playgroud)

为什么第一次出现错误?

>>> a.send(0)
StopIteration 
Run Code Online (Sandbox Code Playgroud)

为什么第一个send()要求为None?与此错误一样:

>>> a.send(0)
Traceback (most recent call last):
    <ipython-input-222-4abef3782000> in <module>()
TypeError: can't send non-None value to a just-started generator
Run Code Online (Sandbox Code Playgroud)

然后第一次发送启动生成器(我不知道为什么),我发送一个'0'然后打印它,但第二个0再次没有,并恢复与我发送它(0这里)

>>> a.send(None)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
Run Code Online (Sandbox Code Playgroud)

这个链接对Python 3:发送器的发送方法没有多大帮助

Aug*_*ack 8

问题1:为什么第一次出现错误?

第一次没有错误,在python2.7和python3.3上测试:

>>> def test():
...     for x in xrange(10):
...         res = yield
...         yield res
... 
>>> a = test()
>>> next(a)
>>> next(a)
>>> next(a)
>>> next(a)
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
Run Code Online (Sandbox Code Playgroud)

问题2:为什么第一个send()要求为None?

您不能send()第一次使用值,因为生成器直到您拥有yield语句的位置才执行,因此与该值无关.

以下是pep的相关段落,介绍了与生成器共同例程的特性(http://www.python.org/dev/peps/pep-0342/):

因为生成器迭代器在生成器函数体的顶部开始执行,所以在刚刚创建生成器时没有yield表达式来接收值.因此,当生成器迭代器刚刚启动时,禁止使用非None参数调用send(),如果发生这种情况,则会引发TypeError(可能是由于某种逻辑错误).因此,在您与协程通信之前,必须首先调用next()或发送(None)以将其执行推进到第一个yield表达式

一个小小的演练:

def coro():
   print 'before yield'
   a = yield 'the yield value'
   b = yield a
   print 'done!'
 c=coro() # this does not execute the generator, only creates it

 # If you use c.send('a value') here it could _not_ do anything with the value
 # so it raises an TypeError! Remember, the generator was not executed yet,
 # only created, it is like the execution is before the `print 'before yield'`

 # This line could be `c.send(None)` too, the `None` needs to be explicit with
 # the first use of `send()` to show that you know it is the first iteration
 print next(c) # will print 'before yield' then 'the yield value' that was yield

 print c.send('first value sent') # will print 'first value sent'

 # will print 'done!'
 # the string 'the second value sent' is sent but not used and StopIterating will be raised     
 print c.send('the second value sent') 

 print c.send('oops') # raises StopIterating
Run Code Online (Sandbox Code Playgroud)