Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
184 views
in Technique[技术] by (71.8m points)

python - Send method using generator. still trying to understand the send method and quirky behaviour

Here is a little function i wrote to understand the send method:

>>> 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)

Why is there an Error the first time?

>>> a.send(0)
StopIteration 

Why does it require for the first send() to be None? as with this error:

>>> 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

And then the first send starts the generator( i dont know why) and i send a '0' and it prints it but the second 0 is again none and resumes with whatever i send it(0 here)

>>> a.send(None)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0

This link doesnt help much Python 3: send method of generators

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Question 1: Why is there an Error the first time?

There is no Error the first time, tested on python2.7 and 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

Question 2: Why does it require for the first send() to be None?

You can't send() a value the first time because the generator did not execute until the point where you have the yield statement, so there is nothing to do with the value.

Here is the relevant paragraph from the pep that introduced the feature of co-routines with generators (http://www.python.org/dev/peps/pep-0342/):

Because generator-iterators begin execution at the top of the generator's function body, there is no yield expression to receive a value when the generator has just been created. Therefore, calling send() with a non-None argument is prohibited when the generator iterator has just started, and a TypeError is raised if this occurs (presumably due to a logic error of some kind). Thus, before you can communicate with a coroutine you must first call next() or send(None) to advance its execution to the first yield expression

A tiny walkthrough:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...