Since python 2.5 there is the ability to send(), throw(), close() into a generator. Inside the defined generator one can 'catch' the sent data by doing something like:
def gen():
while True:
x = (yield)
if x == 3:
print('received 3!!')
break
else:
yield x
What i am trying to play with is doing something like:
def gen2():
while True:
yield (yield)
Noticed that it is a legal generator which does something..
First thing i'm trying to figure out is:
Is there a good usage for such writing?
Also when doing something like:
g = gen2()
next(g)
g.send(10) # output: 10
g.send(2) # output: nothing
g.send(3) # output: 3
g.send(44) # output: nothing
Why each second 'send' does not do anything?
解决方案
yield (yield) first yields None from the inner yield. It then receives a value from send or next. The inner yield evaluates to this received value, and the outer yield promptly yields that value.
Each yield conceptually has two parts:
Transmit a value to the caller of send or next.
Receive a value from the next send or next call.
Similarly, each send or next conceptually has two parts:
Transmit a value to the yield expression that the generator is currently paused at. (This value is None for next.)
Receive a value from the next yield expression.
The most confusing part of the system is probably that these parts are staggered. The two parts of a yield correspond to two different invocations of send or next, and the two parts of a send or next correspond to two different yields.
If we work through a simple example:
def gen():
print('Not ran at first')
yield (yield)
g = gen() # Step 1
print(next(g)) # Step 2
print(g.send(1) # Step 3
g.send(2) # Step 4
Here's how things work out:
Inside the generator Outside the generator
Step 1
g calls gen()
g returns a generator object
without executing the print
just yet statement.
>>> g
Step 2
next(g) sends None to g
g receives None, ignores it
(since it is paused at the start
of the function)
g prints ('not ran at first')
g executes the "transmit" phase
of the inner yield, transmitting
None
next(g) receives None
Step 3
g.send(1) sends 1 to g
g executes the "receive" phase
of the inner yield, receiving 1
g executes the "transmit" phase
of the outer yield, transmitting 1
g.send(1) receives 1 from g
Step 4
g.send(2) sends 2 to g
g executes the "receive" phase
of the outer yield, receiving 2
g reaches the end of gen and raises
a StopIteration
g.send(2) raises the StopIteration
from g