一言で表すと「関数を途中でストップ・リスタートする機能」です。
デバッガ(pdb.set_trace()
)の途中でストップするのと少し似ているかもしれません。
呼び出すと、引数をそのままprintしてくれる関数を作ってみます。
# 参考: https://qiita.com/koshigoe/items/054383a89bd51d099f10
import functools
def main():
receiver1 = test_coroutine1()
next(receiver1) # 初回のyield文までたどり着くために必要。
receiver1.send(1) # => v: 1
receiver1.send(2) # => v: 2
receiver1.send(3) # => v: 3
receiver2 = test_coroutine2()
receiver2.send(10) # => v: 10
receiver2.send(20) # => v: 20
receiver2.send(30) # => v: 30
def coroutine(func):
@functools.wraps(func)
def wrapper(*args, **kargs):
g = func(*args, **kargs)
next(g)
return g
return wrapper
def test_coroutine1():
while True:
print("---")
v = yield
print("v: {}".format(v))
@coroutine
def test_coroutine2():
while True:
print("---")
v = yield
print("v: {}".format(v))
if __name__ == "__main__":
main()
基本は以下です。
def test_coroutine1():
while True:
print("---")
v = yield
print("v: {}".format(v))
receiver1 = test_coroutine1()
next(receiver1) # 初回のyield文までたどり着くために必要。
receiver1.send(1) # => v: 1
処理の概要は以下のようになっています。
・test_coroutine1が呼ばれた時点では、関数の中は1文字も処理されていません。
・next(receiver1)
の実行により、yield
の行まで処理が進みます。
(print("---")
がなされる)
・その後はreceiver1.send(引数)
とすると、処理が進みます。
yield
構文があると、またそこで処理が止まります。
test_coroutine2
関数はnext
がなくても、最初からsendを送ることができる状態となっています。
これはデコレータによるものです。
詳細な機能はDecorator - Pyデザパタに譲りますが、
デコレータは、関数の前に特定の処理(coroutine
関数の中の処理)を行うことができます。
そのため、関数を動かす前に、必ずnext()
を挟むようになっています。
実際はデコレータつきのコルーチンが作られることの方が多いようです。
一般的には非同期処理などで使用される例などがあります。
コルーチンを使用することでデザインパターンを効率的に書くことができることもあるようです。