When the caller executes
R = m.send(a)
, it puts the objecta
into the generator's input slot, transfers control to the generator, and waits for a response. The generator receives objecta
as the result ofX = yield i
, and runs until it hits another yield expression e.g.Y = yield j
. Then it putsj
into its output slot, transfers control back to the caller, and waits until it gets resumed again. The caller receives j as the result ofR = m.send(a)
, and runs until it hits anotherS = m.send(b)
statement, and so on.
R = next(m)
is just the same asR = m.send(None)
; it's putting None into the generator's input slot, so if the generator checks the result ofX = yield i
thenX
will beNone
.
def coroutine():
for i in range(1, 10):
print("From generator {}".format((yield i)))
>>> c = coroutine()
>>> c.send(None) # same as next(c)
>>> try:
while True:
print("From user {}".format(c.send(1)))
except StopIteration: pass
From generator 1
From user 2
From generator 1
From user 3
From generator 1
From user 4
...
other = yield foo
は「foo
をyield
して返ってきたvalueをother
に渡してください」というイメージ。つまりyield
してからvalueをother
に渡すまでに若干のラグがある(ことが多い)。
yield
もsend
も一度処理を行うと(イメージ的には)そこで一時停止してvalueを受け取るまで次に進まない。print(yield i)
はyield
したi
を表示するのではなくyield
した後に返ってきたvalueを表示する。
def foo():
while True:
x = yield
print(x)
>>> gen = foo()
>>> gen.send(None) #runs up to yield statement
>>> print(gen.send("foo"))
foo
None #since nothing is yielded back inside of foo func.
def foo():
while True:
x = yield
print(x)
yield x
>>> gen = foo()
>>> gen.send(None) #runs up to yield statement
>>> print(gen.send("foo"))
foo
foo
-
c.send(None)
によりcoroutine関数内のiterationが始まる(i = 1)。print("From generator {}".format((yield i)))
により1
を返す。ここでストップ。※まだi
のvalueが返ってきてないのでプリントはしない。i
のvalue受取待ち状態。(上で示したラグ) -
while
文へ移動。c
にvalue1
を送る。value受取待ち状態。 -
c
関数内へ移動。while
文より送られてきたvalue1
を受け取りそのvalueをプリントする。(=From generator 1) -
c
関数内のiterationを続行。1
だったi
を2
にしてyield
する。ここでストップ。 -
while
文へ移動(ステップ2よりvalue受取待ち状態)。関数c
より送られてきたi=2
を受取プリントする(From user 2)。 - ステップ2, 3, 4...と
i
が9
になるまで繰り返す。9
になるとNone
をyield
してiterationが終了する。
上でも何度か示したがgenerator.send(None)
とnext(generator)
は同じ役割を持つ。最初のyield
文にたどり着くための橋渡しと考えて良い。