英語の yield は生産を意味します。初めて Python に触れたとき、私は非常に混乱し、yield の使い方がわかりませんでした。
次の例のように、 yield を使用して関数の戻り値にデータを詰め込むことができることは大まかに知っています:
def addlist(alist): for i in alist: yield i + 1
alist の各項目を取り出し、それに i + 1 を詰め込む。次に、呼び出して各項目を取り出します:
alist = [1, 2, 3, 4] for x in addlist(alist): print x,
これは実際に yield アプリケーションの例です
1. yield を含む関数
yield を含む関数が表示された場合、それはこの関数がジェネレーターであることを意味します。であり、その実行は他の通常の関数とは大きく異なります。たとえば、次の単純な関数:
def h(): print 'To be brave' yield 5 h()
h() を呼び出した後、print ステートメントが実行されていないことがわかります。これは yield ですが、print ステートメントを実行するにはどうすればよいでしょうか?これについては後で説明します。この後の議論と検討を通じて、収量がどのように機能するかが理解できるようになります。
2. Yield は式です
Python 2.5 より前では、yield はステートメントでしたが、Python 2.5 では、yield は次のような式 (Expression) になりました。
m = yield 5
expression (yield 5 )は m に代入されるため、m = 5 と考えるのは間違いです。では、戻り値 (yield 5) を取得するにはどうすればよいでしょうか?後で紹介する send(msg) メソッドを使用する必要があります。
3. next() ステートメントを通して原理を見てみましょう
それでは、収量の動作原理を明らかにしましょう。上記の h() は、yield 式を持っているため、呼び出された後に実行されなかったことがわかっているため、next() ステートメントを通じて実行させます。 next() ステートメントは、次の yield 式までジェネレーターの実行を再開します。例:
def h(): print 'Wen Chuan' yield 5 print 'Fighting!' c = h() c.next()
c.next() が呼び出された後、h() は yield 5 に到達するまで実行を開始するため、出力結果は次のようになります:
Wen Chuan
c.next() を呼び出したとき再度、次の yield 式が見つかるまで実行が継続されます。後でyieldがないため、例外がスローされます:
Wen Chuan Fighting! Traceback (most recent call last): File "/home/evergreen/Codes/yidld.py", line 11, in <module> c.next() StopIteration
4. send(msg)とnext()
next()がどのようにyieldを含む関数を実行するかを理解した後、次を見てみましょう。もう 1 つは非常に重要な関数 send(msg) です。実際、 next() と send() は、ある意味では同様の関数を持っています。違いは、send() は yield 式の値を渡すことができるのに対し、next() は特定の値を渡すことができず、None のみを渡すことができるということです。したがって、
c.next() と c.send(None) は同じ効果があることがわかります。
この例を見てください:
def h(): print 'Wen Chuan', m = yield 5 # Fighting! print m d = yield 12 print 'We are together!' c = h() c.next() #相当于c.send(None) c.send('Fighting!') #(yield 5)表达式被赋予了'Fighting!'
出力結果は次のとおりです:
Wen Chuan Fighting!
初めて呼び出すときは、next() ステートメントを使用するか、send(None) してください。 ) の場合、send を使用して None 以外の値を送信することはできません。そうしないと、この値を受信する yield ステートメントがないため、エラーが発生します。
5. send(msg) と next() の戻り値
send(msg) と next() の戻り値は、次の yield 式のパラメーターを返します。たとえば、yield 5 の場合、5 が返されます。ここで何か理解できましたか?この記事の最初の例では、alist の for i を介してジェネレーターをトラバースすることにより、alist.Next() が実際に毎回呼び出され、毎回の alist.Next() の戻り値が yield のパラメーターになります。何かが押し込まれているのではないかと思い始めます。上記の例を続けてみましょう:
def h(): print 'Wen Chuan', m = yield 5 # Fighting! print m d = yield 12 print 'We are together!' c = h() m = c.next() #m 获取了yield 5 的参数值 5 d = c.send('Fighting!') #d 获取了yield 12 的参数值12 print 'We will never forget the date', m, '.', d
出力結果:
Wen Chuan Fighting! We will never forget the date 5 . 12
6. throw() と close() でジェネレーターを中断します
ジェネレーターの中断は非常に柔軟な手法であり、スローすることができます。 through throw GeneratorExit 例外をスローして、ジェネレーターを終了します。実際、Close() メソッドには同じ機能があり、内部で throw(GeneratorExit) を呼び出します。見てみましょう:
def close(self): try: self.throw(GeneratorExit) except (GeneratorExit, StopIteration): pass else: raise RuntimeError("generator ignored GeneratorExit") # Other exceptions are not caught
したがって、close() メソッドを呼び出してから next() または send(msg) を呼び出すと、例外がスローされます。