The confusion here is that the generator expression is doing a hidden yield
. Here it is in function form:
def foo():
for x in range(10):
yield (yield x)
When you do a .send()
, what happens is the inner yield x
gets executed, which yields x
. Then the expression evaluates to the value of the .send
, and the next yield yields that. Here it is in clearer form:
def foo():
for x in range(10):
sent_value = (yield x)
yield sent_value
Thus the output is very predictable:
>>> a = foo()
#start it off
>>> a.next()
0
#execution has now paused at "sent_value = ?"
#now we fill in the "?". whatever we send here will be immediately yielded.
>>> a.send("yieldnow")
'yieldnow'
#execution is now paused at the 'yield sent_value' expression
#as this is not assigned to anything, whatever is sent now will be lost
>>> a.send("this is lost")
1
#now we're back where we were at the 'yieldnow' point of the code
>>> a.send("yieldnow")
'yieldnow'
#etc, the loop continues
>>> a.send("this is lost")
2
>>> a.send("yieldnow")
'yieldnow'
>>> a.send("this is lost")
3
>>> a.send("yieldnow")
'yieldnow'
EDIT: Example usage. By far the coolest one I've seen so far is twisted's inlineCallbacks
function. See here for an article explaining it. The nub of it is it lets you yield functions to be run in threads, and once the functions are done, twisted sends the result of the function back into your code. Thus you can write code that heavily relies on threads in a very linear and intuitive manner, instead of having to write tons of little functions all over the place.
See the PEP 342 for more info on the rationale of having .send
work with potential use cases (the twisted example I provided is an example of the boon to asynchronous I/O this change offered).
Best Answer
You can also
send
values to generators. If no value is sent thenx
isNone
, otherwisex
takes on the sent value. Here is some info: http://docs.python.org/whatsnew/2.5.html#pep-342-new-generator-features