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
The send() method returns the next value yielded by the generator, or raises StopIteration if the generator exits without yielding another value.
Create Generators in Python It is fairly simple to create a generator in Python. It is as easy as defining a normal function, but with a yield statement instead of a return statement. If a function contains at least one yield statement (it may contain other yield or return statements), it becomes a generator function.
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
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
The send()
can only be called if generator is waiting at yield. Since your generator hasn't started executing, calling send()
gives you the first error.
Further more, each yield in the generator consumes the value sent by send()
. When the second yield statement consumes value but it doesn't use it so that value is discarded. Then you wait on first yield which does consumes value from send()
and that value is printed out. So you end up with needing two send()
.
Here's the fixed version:
>>> def echo():
... while True:
... val = (yield)
... yield val
...
>>> g=echo()
>>> next(g) # move to 1st yield
>>> g.send(2) # execution stops at 2nd yield
2
>>> next(g) # execution stops at 1st yield
>>> g.send(3) # execution stops at 2nd yield
3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With