pythonのyieldキーワード
反復可能オブジェクト
mylist
は反復可能なオブジェクトです.リスト生成式を使用してリストを作成すると、反復可能なオブジェクトが作成されます.mylist = [x*x for x in range(3)]
for i in mylist :
print(i)
0
1
4
ここでは、すべての値がメモリに存在するため、大量のデータには適していません.
ビルダー
yieldキーワード
yield
はreturn
のようなキーワードですが、この関数はジェネレータ def createGenerator() :
mylist = range(3)
for i in mylist :
yield i*i
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
for i in mygenerator:
print(i)
0
1
4
最初の反復では関数が実行され、最初からyieldキーワードに到達し、yield後の値を最初の反復の戻り値として返します.その後、この関数を実行するたびに、関数内で定義したループの次のループを実行し続け、戻ることができないまでその値を返します.
反復器、次にジェネレータを理解し、最後にyeildの機能を見て、yieldに遭遇すると戻りますが、ジェネレータを返します.mygenerator = createGenerator() # create a generator .
また、ネット上では、説明も悪くない文章を見ました.https://blog.csdn.net/mieleizhi0522/article/details/82142856?utm_source=blogxgwz0
もしあなたがまだyieldに対して初歩的な認識を持っていないならば、あなたはまずyieldを“return”と見なして、これは直観的で、それはまずreturnで、普通のreturnはどういう意味で、プログラムの中である値を返して、帰ってからプログラムはもう下へ実行しません.returnを見てからジェネレータ(generator)の一部(yield付きの関数こそ本当の反復器)と見なします.よし、これらが分からない場合は、yieldをreturnと見なして、次のプログラムを直接見ると、yieldのすべての意味がわかります.
def foo():
print("starting...")
while True:
res = yield 4
print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(next(g))
しゅつりょく
starting...
4
********************
res: None
4
コードの実行順序を直接説明します.コードの単一ステップデバッグに相当します.
1.プログラムが実行を開始すると、foo関数にyieldキーワードがあるため、foo関数は実際に実行されるのではなく、まずジェネレータg(オブジェクトに相当)が得られる
2.nextメソッドが呼び出されるまでfoo関数は正式に実行を開始し、foo関数のprintメソッドを実行してからwhileループに入ります.
3.プログラムはyieldキーワードに出会って、それからyieldをreturnと考えて、returnは1つの4の後で、プログラムは停止して、res操作に値を割り当てることを実行していないで、この時next(g)文の実行は完成して、だから出力する前の2行(1つ目はwhileの上のprintの結果で、2つ目はreturnの出た結果)はprint(next(g))を実行する結果で、
4.プログラム実行print(「*」*20)、出力20個*
5.また次のprint(next(g))を実行し始めます.このときは上とあまり差がありませんが、このときはさっきのnextプログラムが停止したところから実行されます.つまりresの付与操作を実行するので、注意してください.このとき賦値操作の右側には値がない(さっきはreturnが出ていたので、賦値操作の左にパラメータが渡されていない)ので、このときres賦値はNoneなので、次の出力はres:Noneです.
6.プログラムはwhileで実行され続け、yieldに再び遭遇します.このときもreturnが4を出し、プログラムが停止します.print関数が出力する4が今回のreturnが4を出ます.
def foo():
print("starting...")
while True:
res = yield 4
print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(g.send(7))
このジェネレータのsend関数の例を見て、この例は上の例の最後の行を交換して、結果を出力します.
starting...
4
********************
res: 7
4
まずsend関数の概念を大まかに説明します:この時あなたは上のあの紫色の字に気づくべきで、それから上のあのresの値はどうしてNoneで、これは7になって、いったいどうして、これはsendが1つのパラメータをresに送ったので、上で述べたように、returnの時、4をresに与えていないので、次回実行する時は賦値操作を続けるしかありません.仕方なくNoneとして付与し、sendを使用すると、実行を開始するときは、前回(return 4以降)に続いて実行し、まず7をresに付与し、nextの役割を実行し、次回のyieldに出会ってreturnが結果を出して終了する.
5.プログラムはg.send(7)を実行し、yieldキーワードの行から下へ実行し続け、sendは7という値をres変数に付与する
6.sendメソッドにnext()メソッドが含まれているため、プログラムはprintメソッドを実行し続け、whileループに再び進みます.
7.プログラム実行は再びyieldキーワードに遭遇し、yieldは後の値を返した後、nextメソッドまたはsendメソッドが再び呼び出されるまでプログラムは再び一時停止する.
なぜこのジェネレータを使うのかというと、Listを使うと、0,1,2,3,4,5,6を取るなど、より大きなスペースを占めるからです.1000
あなたはそうするかもしれません.
for n in range(1000):
a=n
このときrange(1000)はデフォルトで1000個の数を含むlistを生成するので、メモリを占めています.
このとき先ほどのyieldをジェネレータに組み合わせて実装したり、xrange(1000)というジェネレータで実装したりすることができます
yieldの組み合わせ:
def foo(num):
print("starting...")
while num<10:
num=num+1
yield num
for n in foo(0):
print(n)
出力:
starting...
1
2
3
4
5
6
7
8
9
10