When the caller executes
R = m.send(a), it puts the objectainto the generator's input slot, transfers control to the generator, and waits for a response. The generator receives objectaas the result ofX = yield i, and runs until it hits another yield expression e.g.Y = yield j. Then it putsjinto 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 ithenXwill 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文にたどり着くための橋渡しと考えて良い。