1. ホーム
  2. パイソン

[解決済み】Pythonジェネレータの「send」関数は何のためにあるのか?

2022-04-12 06:51:44

質問

Pythonのジェネレータ関数に付随する"send"関数がなぜ存在するのか、どなたか例を教えてください。yield関数は十分理解しています。しかし、send関数は私には分かりにくいです。このメソッドに関するドキュメントは複雑です。

generator.send(value)

実行を再開し、ジェネレータ関数に値を「送信」します。value引数は、現在のyield式の結果になります。send()メソッドは、ジェネレータが生成した次の値を返すか、別の値を生成せずにジェネレータが終了した場合はStopIterationを発生させます。

どういう意味ですか?valueって関数の入力じゃなかったっけ?send()メソッドはジェネレータが生成した次の値を返す」というのは、yield関数の目的そのものでもあるような...。

誰か、yield ではできないことを実現する send を利用したジェネレータの例を教えてください。

どのように解決するのですか?

これは、ちょうど収量したジェネレーターに値を送るために使用します。ここでは、人工的な(役に立たない)説明の例を示します。

>>> def double_inputs():
...     while True:
...         x = yield
...         yield x * 2
...
>>> gen = double_inputs()
>>> next(gen)       # run up to the first yield
>>> gen.send(10)    # goes into 'x' variable
20
>>> next(gen)       # run up to the next yield
>>> gen.send(6)     # goes into 'x' again
12
>>> next(gen)       # run up to the next yield
>>> gen.send(94.3)  # goes into 'x' again
188.5999999999999

だけではできません。 yield .

なぜこれが便利なのかというと、私が見た中で最も良い使用例のひとつが、Twistedの @defer.inlineCallbacks . 本来はこのような関数を書くことができるのです。

@defer.inlineCallbacks
def doStuff():
    result = yield takesTwoSeconds()
    nextResult = yield takesTenSeconds(result * 10)
    defer.returnValue(nextResult / 10)

何が起こるかというと takesTwoSeconds() が返されます。 Deferred これは、後で計算される値を約束するものです。Twistedは、別のスレッドで計算を実行することができます。計算が終わると、それをディファレンシャルに渡し、その値は再び doStuff() 関数があります。このように doStuff() は,あらゆる種類の計算やコールバックなどを行うことができることを除けば,多かれ少なかれ通常の手続き型関数と同じように見えるはずです.この機能を使う前の選択肢としては、以下のようなものがあります。

def doStuff():
    returnDeferred = defer.Deferred()
    def gotNextResult(nextResult):
        returnDeferred.callback(nextResult / 10)
    def gotResult(result):
        takesTenSeconds(result * 10).addCallback(gotNextResult)
    takesTwoSeconds().addCallback(gotResult)
    return returnDeferred

もっと複雑で扱いにくいものです。