ホームページ >バックエンド開発 >Python チュートリアル >Python のジェネレーターはどのように機能するのでしょうか?

Python のジェネレーターはどのように機能するのでしょうか?

WBOY
WBOY転載
2023-04-24 19:46:051064ブラウズ

Python ジェネレーターとは

ジェネレーターは特別な反復子であり、その中には __iter__ メソッドと __next__ メソッドも含まれています。場合によっては、ループを終了するために StopIteration 例外がスローされることがありますが、イテレーターと比較して、ジェネレーターには「中間値」を保存する機能もあります。次回実行するときにも、この「中間値」を操作します。ジェネレーターのキーワードは yield です。以下に最も単純なジェネレーターを書いてみましょう。

#!/usr/bin/env python

def printNums():
    i = 0
    while i<10:
        yield i
        i = i + 1


def main():
    for i in printNums():
        print(i)

if __name__ == &#39;__main__&#39;:
    main()

パッとコードを見ると「何これ?」と思うかもしれませんが、yield## を使わずに range を使って生成してみてはいかがでしょうか#? ああ、心配しないでください。ジェネレーターがなぜ必要なのか、またはジェネレーターがどのような問題を解決するのかを見ていきましょう。

Python ジェネレーターが必要な理由

この問題を説明する前に、まず 0 ~ 10000000 の範囲でデータを出力する要件を作成し、実行してエクスポートされたメモリ操作のスクリーンショットを表示しましょう。

Python プログラム メモリ情報を呼び出すための補助命令

ここでは、

pythonmemory_profiler モジュールを使用して、プログラム メモリの占有を検出できます。

インストール

memory_profilerライブラリ:

pip3 install memory_profiler

使用方法は非常に簡単で、必要な関数またはコードの前に

@profile デコレータを追加するだけです。例:

@profile
def main():
    pass

Generate

.dat file

mprof run

Exportアイコンを使用すると、

mprof plot --output=filename

python case code

次の 2 つのプログラムはどちらも 0 ~ 9999999 のデータを出力します。違いは、最初のプログラムでは

range を使用してから append into list を使用するのに対し、2 番目のプログラムでは反復子を使用してデータを生成することです。

main.pyプログラム

@profile
def main():
    data = list(range(10000000))
    for i in data:
        pass

if __name__ == &#39;__main__&#39;:
    main()

main_2.pyプログラム

def printNum():
    i = 0 
    while i < 10000000:
        yield i
        i = i + 1

@profile
def main():
    for i in printNum():
        pass

if __name__ == &#39;__main__&#39;:
    main()

実行中のプログラム

コードこれで、上記のようにプログラムを実行してメモリ情報をエクスポートできます

Python のジェネレーターはどのように機能するのでしょうか?

実行後にメモリ情報を表示します

main.py 実行メモリ グラフ

Python のジェネレーターはどのように機能するのでしょうか?

main_2.py 実行メモリ グラフ

Python のジェネレーターはどのように機能するのでしょうか?

比較上の 2 つの図では、データをリストに重ね合わせて出力すると、400M 近くのメモリが消費されますが、イテレータを使用して次の値を計算すると、16M のメモリしか使用されません。

上記の事例を通じて、なぜジェネレーターを使用する必要があるのか​​を理解する必要があります。

Python ジェネレーターの原理

ジェネレーター式

yield ステートメントには、python 解釈権の内部機構が含まれるため、ソース コードを参照することが困難です。その原理を理解するのは困難ですが、yield の一時停止メカニズムを使用してジェネレーターを探索することができます。

次のコードを記述できます。

def testGenerator():
    print("进入生成器")
    yield "pdudo"
    print("第一次输出")
    yield "juejin"
    print("第二次输出")

def main():
    xx = testGenerator()
    print(next(xx))
    print(next(xx))

if __name__ == &#39;__main__&#39;:
    main()

操作後の効果は次のとおりです。

Python のジェネレーターはどのように機能するのでしょうか?

上記の例を、次のジェネレーターの操作プロセスは、ジェネレーターの感覚を深めます。

python

yield ステートメントに遭遇すると、現在の関数の実行ステータスが記録され、実行が一時停止され、結果がスローされます。 __next__ メソッドの次の呼び出しを待ち続けます。このメソッドが呼び出された後、関数は次の yield ステートメントまたは関数の終了まで実行を再開します。 ##関数が実行可能になると、ジェネレーターの終了をマークするために StopIteration がスローされます。 ジェネレーター式

python

では、ジェネレーターは、関数に記述して

yield

を使用して返すだけでなく、直接使用することもできます。表現、そうですね。 。 。抽象的かもしれませんが、以下のコードを見れば理解できると思います。 <pre class="brush:py;">def printNums(): for i in [1,2,3,4,5]: yield i def main(): for i in printNums(): print(i) gener = (i for i in [1,2,3,4,5]) for i in gener: print(i) if __name__ == &amp;#39;__main__&amp;#39;: main()</pre>このうち、コード (i for i in [1,2,3,4,5])

printNums

関数と同等であり、そのコンテナーのタイプが生成されるので、type を使用してそれを印刷して確認できます。 コードを変更すると、出力は次のようになります:

以上がPython のジェネレーターはどのように機能するのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。