Reputation: 3174
I am trying to understand some of the subtle details of python generators. One of the test programs I wrote to see if I could both send and read alternatively values to/from the same generator is the following:
def injector():
while True:
try:
print 'a'
v = yield
print 'b', v
yield v
print 'c'
except GeneratorExit:
print 'exit'
break
g = injector()
print 'send none'
g.send(None)
print 'send 2'
g.send(2)
print 'receiving'
v = g.next()
print 'received', v
g.close()
The expected output for this program is:
send none
a
send 2
b 2
receiving
received 2
c
a
exit
The output I get is:
send none
a
send 2
b 2
receiving
c
a
received None
exit
Now, obviously, the question is why am I getting the above output ? What is it that I did not understand about how generators work ?
Upvotes: 2
Views: 143
Reputation: 91017
Let me try to clarify:
def injector():
while True:
try:
print 'a'
v = yield
print 'b', v
yield v
print 'c'
except GeneratorExit:
print 'exit'
break
g = injector()
print 'send none'
g.send(None)
Here the coroutine is started. It executes until the first yield whose result is returned from .send()
, but then discarded.
The coroutine prints a
and yields nothing, thus None
. So it is ok to discard.
print 'send 2'
g.send(2)
Here you send a 2 to the coroutine, making it continue where you left it. v = 2
.
It prints 2
and yields v
again. You would expect that from the g.send()
call.
So after receiving and discarding v
, you do
print 'receiving'
v = g.next()
Here you give control to the coroutine again, which prints c
, then a
, then yields None
again, which you get here.
print 'received', v
thus prints None
for v
.
What you probably want is
g = injector()
print 'send none'
g.send(None)
print 'send 2'
v = g.send(2)
print 'received', v
g.close()
(Note that this last block can be written more cleanly and nicely as follows:
from contextlib import closing
with closing(injector()) as g:
print 'send none'
g.send(None)
print 'send 2'
v = g.send(2)
print 'received', v
)
Upvotes: 3
Reputation: 39698
So, the issue you are having is the last call. First of all, it appears to be starting where the code left off, printing the 'c'
first. Then as the statement was not yielded, it continues in the while loop, printing 'a'
. Finally, the output is produced. The none results because nothing is yielded after the 'a'
Upvotes: 0