Pythonはyieldを深く理解する

3440 ワード

ただ、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アプリケーションの一例ですが、limodouの文章「2.5版yieldの学習心得」を見て、自分で繰り返し体験した後、yieldに対して新しい理解を得ました.
1.yieldを含む関数
ある関数にyieldが含まれているのを見たら、この関数はすでにGeneratorであり、その実行は他の一般的な関数とは多くの違いがあることを意味します.たとえば、次の簡単な関数です.
def h():
    print 'To be brave'
    yield 5

h()は、h()を呼び出した後、print文が実行されていないことを示します.これがyieldです.では、print文を実行するにはどうすればいいのでしょうか.これが後で議論する問題で、後の議論と学習を通じてyieldの動作原理がわかります.
2.yieldは式です
Python2.5以前は、yieldは文でしたが、2.5では、yieldは式(Expression)です.たとえば、次のようになります.
m=yield 5式(yield 5)の戻り値はmに与えられるので,m=5は誤りであると考えられる.では、(yield 5)の戻り値をどのように取得しますか?後述するsend(msg)メソッドを使用する必要があります.
3.next()文を通して原理を見る
では、yieldの動作原理を説明します.yield式があるため、上のh()が呼び出されても実行されないことを知っています.そのため、next()文で実行させます.next()文は、次のyield式までGenerator実行を復元します.例:
def h():
    print 'Wen Chuan'
    yield 5
    print 'Fighting!'
c = h()

c.next()c.next()呼び出し後、yield 5に遭遇するまでh()が実行を開始するので、結果を出力する:
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を含む関数をどのように実行するかを理解した後,もう一つの非常に重要な関数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を返します.ここまで来て、何か分かったのではないでしょうか.本明細書の第1の例では、for i in alistによってGeneratorを巡回するが、実際には毎回alistが呼び出される.毎回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()割り込みGenerator
Generatorを中断するのは非常に柔軟なテクニックで、throwがGeneratorExit異常を投げ出すことでGeneratorを終了することができます.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)を呼び出すと、例外が放出されます.
Traceback (most recent call last):
  File "/home/evergreen/Codes/yidld.py", line 14, in <module>
    d = c.send('Fighting!')  #d    yield 12     12
StopIteration