この記事を読むのに約3.6分かかります。
Yieldは、ジェネレーターとコルチンを実装できます。ジェネレーターとは何か、コルティンとは何か、それでも理解できない場合は、見下ろし続けることができます。その機能と効果を理解している限り、概念を理解する必要はありません。
まず、英語のyieldの意味を見てください。
to produce or provide sth, for example a profit, result or crop
中国の意味:生産(作物);生産(収入、利益など);提供。
Pythonを初めて学んだとき、yieldキーワードに出会ったとき、それは特別な種類のリターンであると理解しました。理解でき、自分で使用することはめったになかったので、深く研究しませんでした。今までは大量のデータを処理する必要があり、データのサイズはコンピューターの空きメモリーを超えていましたが、今回は歩留まりを考えています。たとえば、db2データベースを操作してデータをクエリします。データの結果が非常に大きい場合、一度にメモリに読み込みたくありません。yieldキーワードを使用してデータの行を返します。プログラムが処理されたら、次の行をフェッチします。
def read(self, sql, params=()):
stmt = ibm_db.prepare(self.connection, sql)for index, param inenumerate(params):
ibm_db.bind_param(stmt, index +1, param)
ibm_db.execute(stmt)
row = ibm_db.fetch_tuple(stmt)while row:yield row
row = ibm_db.fetch_tuple(stmt)
キーワードyieldの使用法は、次のように理解できます。値は返されますが、プログラムは終了しません。次回、yieldの背後にあるコードは、コードがなくなるまで実行され続け、操作が終了します。ここでは、効果を確認するための簡単な例を示します。
>>> def iter_fun():...print("a")...yield1...print("b")...yield2...print("c")...yield3...>>>iter_fun()<generator object iter_fun at 0x107e372a0>>>>for i initer_fun():...print(i)...
a
1
b
2
c
3>>> x =iter_fun()>>> x.__next__()
a
1>>> x.__next__()
b
2>>> x.__next__()
c
3>>> x.__next__()Traceback(most recent call last):
File "<stdin>", line 1,in<module>
StopIteration
上記の例から、yieldキーが自動的にプライベートメソッド__next__を生成するため、すべてのデータが取り出されてメモリに保存されることはありません。メモリスペースを節約したいだけ使用してください。
さらに、データ量が多いと、yieldの実行速度が向上します。
In [14]: def normal_fun(num):...: result =[]...:for i inrange(0,num):...:if i%2==0:...: result.append(i)...:return result
...:
In [14]: def iter_fun(num):...:for i inrange(0,num):...:if i %2==0:...:yield i
...:
In [15]:%time for i initer_fun(1000000): a = i
CPU times: user 97 ms, sys:2.55 ms, total:99.6 ms
Wall time:97.2 ms
In [16]:%time for i innormal_fun(1000000): a = i
CPU times: user 115 ms, sys:13.6 ms, total:129 ms
Wall time:128 ms
In [17]:%time for i innormal_fun(100000000): a = i
CPU times: user 10.8 s, sys:668 ms, total:11.4 s
Wall time:11.4 s
In [18]:%time for i initer_fun(100000000): a = i
CPU times: user 9.1 s, sys:6.49 ms, total:9.11 s
Wall time:9.12 s
上記のコードはIpython端末で実行されます。yieldを使用した関数の方が実行速度が速いことがわかります。
歩留まりは、ジェネレータを自分で実装するための最も便利な方法です。 Python言語のジェネレーターは、最も便利な機能の1つであり、あまり使用されていない機能でもあります。同様の機能があるかどうか、javaを使用している友人に尋ねました。いいえと答えました。インターネットで検索しました。これは確かに主流のプログラミング言語です。なし、したがって、Pythonのジェネレーター機能は、他の言語をPythonに変換するエンジニアの注目を集めていません。
なぜジェネレーターは非常に便利なのですか?
処理する必要のあるデータのサイズがコンピューターの使用可能なメモリーを超える場合、ジェネレーターの遅延ロード(使用時にメモリーへの読み取り)は非常に効果的です。
たとえば、ファイルを読み取るときに次の方法を使用すると、ファイルが特に大きい場合、メモリがすぐにいっぱいになる可能性があります。
withopen("file.txt","r")as reader:for line in reader.readlines():
# do something
pass
推奨される方法は、ファイル自体のジェネレーターを使用して、ファイルのサイズに関係なく、メモリがバーストしないようにすることです。
withopen("file.txt","r")as reader:for line in reader:
# do something
pass
実際、リーダーのメソッドを見ることができます。
>>> withopen("/etc/passwd","r")as reader:...dir(reader)...['_CHUNK_SIZE','__class__','__del__','__delattr__','__dict__','__dir__','__doc__','__enter__','__eq__','__exit__','__format__','__ge__','__getattribute__','__getstate__','__gt__','__hash__','__init__','__init_subclass__','__iter__','__le__','__lt__','__ne__','__new__','__next__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','_checkClosed','_checkReadable','_checkSeekable','_checkWritable','_finalizing','buffer','close','closed','detach','encoding','errors','fileno','flush','isatty','line_buffering','mode','name','newlines','read','readable','readline','readlines','reconfigure','seek','seekable','tell','truncate','writable','write','write_through','writelines']>>>
__iter__メソッドと__next__メソッドがあることがわかります。これら2つのメソッドはジェネレーターの兆候です。
ジェネレーター、イテレーター、およびイテラブルオブジェクトについて詳しく知りたい場合は、以前のツイートを読むことができます。
[ Pythonの基本シリーズ-反復可能なオブジェクト、反復子、およびジェネレーター](http://mp.weixin.qq.com/s?__biz=MzU0OTg3NzU2NA==&mid=2247483827&idx=1&sn=6a661c78b3f0db2e4c94cee1ddc3b036&chksm=fba86
[ イテレーターとジェネレーターの詳細な理解](http://mp.weixin.qq.com/s?__biz=MzU0OTg3NzU2NA==&mid=2247484255&idx=1&sn=cb340bdf3038a8d1715a89a8752c65c5&chksm=fba8610cccd3ccrebdirect4
コルチンの実現を容易にするためのasyncioおよびawaitキーワードがありますが、yieldキーワードもコルチンを実現できます。それ以前は、コルチンの実現はyieldに依存していました。
Yieldにはsendメソッドがあり、yieldの戻り値を変更できます。これは次のように使用されます。最初にコードを見てください。
In [20]: def fun():...:print("a")...: a =yield1...:print("b")...:print("a = ",a)...: b =yield a
...: print("c")...:print("b = ",b)...:
In [21]: x =fun()
In [22]: x.__next__()
a
Out[22]:1
In [23]: x.send(4)
b
a =4
Out[23]:4
In [24]: x.send(5)
c
b =5---------------------------------------------------------------------------
StopIteration Traceback(most recent call last)<ipython-input-24-9183f5e81876>in<module>---->1 x.send(5)
xの__next__メソッドが初めて実行されると、関数は最初のyieldまで実行され、aを出力して、値1を返します。このとき、変数aはyieldの戻り値を取得せず、aはNoneです。x.sendが実行されると(4)、aは値4を取得し、プログラムは2番目のyieldまで実行され、後続のプロセスは同じです。
この機能を使用して、呼び出された関数と通信し、プロデューサーコンシューマーモデルを実装できます。コードは次のとおりです。
import time
def consume():
r =''while True:
n =yield r
if not n:returnprint('[consumer] consuming %s...'% n)
time.sleep(1)
r ='well received'
def produce(c):next(c)
n =0while n <5:
n = n +1print('[producer] producing %s...'% n)
r = c.send(n)print('[producer] consumer return: %s'% r)
c.close()if __name__=='__main__':
c =consume()produce(c)
結果は次のとおりです。
[ producer] producing 1...[consumer] consuming 1...[producer] consumer return: well received
[ producer] producing 2...[consumer] consuming 2...[producer] consumer return: well received
[ producer] producing 3...[consumer] consuming 3...[producer] consumer return: well received
[ producer] producing 4...[consumer] consuming 4...[producer] consumer return: well received
[ producer] producing 5...[consumer] consuming 5...[producer] consumer return: well received
生成関数と消費関数は1つのスレッドで実行され、coroutineの関数は、sendメソッドを呼び出してsendメソッドとyieldを切り替えることで実現されます。
coroutineについて学ぶために、あなたは私の以前のつぶやきを見ることができます:
[ 定期的な研究ノート)(http://mp.weixin.qq.com/s?__biz=MzU0OTg3NzU2NA==&mid=2247483684&idx=1&sn=0a106dcbe89438b4a1d3dd77eadd2900&chksm=fba86377ccdfea6110de27f78e828cfdaacrechat
[ 並行性のためにマルチスレッドまたはコルルーチンを使用しますか? ](http://mp.weixin.qq.com/s?__biz=MzU0OTg3NzU2NA==&mid=2247484280&idx=1&sn=ad46f3ef58ee7739da7d4f98ea97134c&chksm=fba8612bccdfe83d32e78e8ee7feadd4fc4benebd
この記事に興味がある場合は、「フォロー」または「ウォッチング」のサポートを提供してください。 WeChatで「PythonNo。7」を検索し、フォローしてオリジナルの乾物を直接入手してください。
Recommended Posts