2017-12-16 1 views
1

同様の問題については、多くの良い質問があります。ジェネレータへの複数の「送信」コールでPythonはどのように機能しますか?

python generator "send" function purpose?

What does the "yield" keyword do?

バック "送信" の定義に取得することができます:

は、実行を再開し、ジェネレータ関数に値を「送信します」。 value引数は、現在のyield式の結果になります。 send()メソッドは、ジェネレータによって生成された次の値を返します。 は、ジェネレータが別の 値を生成せずに終了した場合にStopIterationを発生させます。センド()が発電を開始するために呼び出されると 値

を受ける可能性がしかし、私は、私は重要な何かをしないのです感じることは降伏式がありませんので、それは、引数としてなしで 呼び出さなければなりません。

def multiplier(): 
    while True: 
     m = yield    # Line #3 
     print('m = ' + str(m)) # Line #4 
     yield str(m * 2)  # Line #5 
     yield str(m * 3)  # Line #6 

#------------------------ 

it = multiplier() 

print('it.send(None): ') 
print(str(it.send(None))) 
print('--------------') 

print('it.send(10): ') 
print(it.send(10)) 
print('--------------') 

print('it.send(100): ') 
print(it.send(100)) 
print('--------------') 

そして、ここでは出力です::

it.send(None): 
None 
-------------- 
it.send(10): 
m = 10 
20 
-------------- 
it.send(100): 
30 
-------------- 

質問:

    ここだけのジェネレータを初期化する None値を持つ最初のものを含む3つの send呼び出し、と私の例です。
  • #5行目でit.send(10)を使用した場合はどうなりますか? の定義に従うと、ジェネレータの実行が再開されます。ジェネレータ は入力値として10を受け入れ、現在のyield expressionで使用します。私の例ではyield str(m * 2)ですが、それではm10に設定されています。いつそれは起こったの。の参照番号がmyieldの3行目のためですか?

  • #6 it.send(10)の行には何が起こりますか?出力はまだ30ですか? 私の以前の質問の参考文献は を一度しか扱っていないことを意味しますか?

注: 私は私の例ビットを変更して、ライン#5、#6、その後print(it.send(10))next(it)を使用する間のラインm = yieldを追加した場合 - その場合には出力が意味をなすために開始します。 20と300

+1

は、あなたのコード内の一つだけ' yield'表現があります。値を送るとしても、 'm'は' while'ループの次の反復まで再割り当てされません。 – vaultah

+0

@vaultahそれはいつ設定されますか? 1回目または2回目の 'send'コールの後に?最初の 'send'は' yield'-sです。もう1つは 'yield'値を変更/設定し、それを' m'に割り当てて、2回目の "yield"呼び出し後に停止しますか? – Axalix

+1

@Axalix最初の 'send'の前にジェネレータの何も実行されませんでした。最初に 'send'を呼び出すと、' m = yield'の 'yield'が入力されるまでジェネレータが実行されます。 2回目の 'send'では、' yield'が 'send'のパラメータで返され、' yield str(m * 2) 'が入力されるまで実行が続けられます。 –

答えて

2

あなたのジェネレータ関数は3つのyield式を持っていますが、そのうちの2つ(5行目と6行目)から値を捨ててしまいます。そこにある値を使って何かをしたら、100がこの関数で使われているのを見るでしょう。例を続けて実行した場合、sendを5回呼ぶと、ジェネレータはmを新しい値に更新します。

あなたの例ではsend呼び出しを行うコードをウォークスルー、および発電機が同時にやっているかを見ることができます:

it = multiplier() 

この時点で、ジェネレータオブジェクトがitに作成され、保存されています。ジェネレータコードはまだ実行されていません。関数コードの開始時に一時停止しています。

print(str(it.send(None))) 

これは、ジェネレータ関数のコードの実行を開始します。送信される値はNoneである必要があります。そうしないとエラーが発生します。関数はその値を決して見ません。 next(it)it.send(None)に相当するため、nextを使用してジェネレータを起動する方が一般的です。

ジェネレータ機能は、最初のyieldが表示される3行目まで実行されます。特定の値を返さないので、sendの戻り値はNone(これは印刷されます)です。

print(it.send(10)) 

この値は、発電機に送られ、そこで10mとして格納されますライン3上yield式の値となり、ライン4上にコード印刷それを発電機機能がラインに実行し続けます5、次のyield式に到達します。 str(m * 2)を生成しているので、呼び出しコードは"20"となり、それを出力します。あなたが表現としてではなく文としてyieldを使用していないので、

print(it.send(100)) 

100値がその値4行にyieldの値として、発電機に送られますが、無視されます。 100を単独で1行に置くのと同じように、これは完全に合法ですが、あまり有用ではないかもしれません。コードは、行番号5に進み、ここでstr(m * 3)、または"30"が生成され、これは呼び出しコードによって出力されます。

あなたの運転コードは停止していますが、発電機はまだ稼動しており、より多くの値を送って戻すことができます。 のように、次の値sendも無視されますが、その次の値は、whileのループがジェネレータのループに戻り、3行目がyieldに達したときに新しいmの値になります。

このコードでのsendの混乱のいくつかは、あなたが式とステートメントの両方としてyieldを使用しているという事実と関係があります。おそらくあなたは両方をしたいと思わないでしょう。通常、ジェネレータに送信されるすべての値を気にするか、そのいずれかを気にしません。複数の値を(例えばn*2n*3のように)生成したい場合は、単一項目ではなくタプルを生成できます。

ここで私はあなたが一緒にプレイし、理解しやすいかもしれないと思うあなたのコードの修正版です: `メートル= yield`:

def multiplier(): 
    print("top of generator") 
    m = yield # nothing to yield the first time, just a value we get 
    print("before loop, m =", m) 
    while True: 
     print("top of loop, m =", m) 
     m = yield m * 2, m * 3   # we always care about the value we're sent 
     print("bottom of loop, m =", m) 

print("calling generator") 
it = multiplier() 

print("calling next") 
next(it) # this is equivalent to it.send(None) 

print("sending 10") 
print(it.send(10)) 

print("sending 20") 
print(it.send(20)) 

print("sending 100") 
print(it.send(100)) 
関連する問題