这是我写的一个小函数来理解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:发送器的发送方法没有多大帮助
第一次没有错误,在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)
您不能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)