ホームページ  >  記事  >  バックエンド開発  >  Python - ジェネレーターの詳細説明

Python - ジェネレーターの詳細説明

巴扎黑
巴扎黑オリジナル
2017-06-23 15:10:061427ブラウズ

1. ジェネレーターとは

リスト生成では、リストを直接作成できます。ただし、メモリの制約により、リストの容量には確実に制限があります。さらに、100 万個の要素を含むリストを作成すると、大量の記憶領域が必要になるだけでなく、最初の数要素にアクセスするだけで済む場合、後続の要素のほとんどが占有する領域が無駄になります。では、リストの要素を特定のアルゴリズムに従って計算できれば、ループ中に後続の要素を継続的に計算できるでしょうか。これにより、完全なリストを作成する必要がなくなり、スペースが大幅に節約されます。 Python では、ループと計算を同時に行うこの仕組みをジェネレーター: ジェネレーターと呼びます。

2. ジェネレーターメソッドを作成する

方法 1

ジェネレーターを作成するには、さまざまな方法があります。 1つ目の方法はとても簡単で、リスト生成の[ ]を( )に変えるだけです

LとGの作成の違いは一番外側の[ ]と( )だけで、Lはリスト、Gは生成デバイスです。 L の各要素を直接出力することはできますが、G の各要素を出力するにはどうすればよいでしょうか?それらを 1 つずつ出力したい場合は、 next() 関数を通じてジェネレーターの次の戻り値を取得できます:


実行結果:

実行結果:

ジェネレーター 保存されるのはアルゴリズムです。 next(G) が呼び出されるたびに、最後の要素が計算されるまで G の次の要素の値が計算され、要素がなくなると StopIteration 例外がスローされます。 。もちろん、この種の next() の連続呼び出しは実際には異常です。ジェネレーターも反復可能なオブジェクトであるため、正しい方法は for ループを使用することです。したがって、ジェネレーターを作成した後は、基本的に next() を呼び出すことはありませんが、for ループを通じて反復処理するため、StopIteration 例外を気にする必要はありません。

方法 2

ジェネレーターは非常に強力です。計算アルゴリズムが比較的複雑で、リスト生成と同様の for ループを使用して実装できない場合は、関数を使用して実装することもできます。

たとえば、有名なフィボナッチ数列では、最初と 2 番目の数値を除き、最初の 2 つの数値を加算することで任意の数値を得ることができます:

1, 1, 2, 3, 5 , 8, 13, 21, 34 , ...

フィボナッチ数列はリスト生成では書けませんが、関数を使って簡単に出力できます:


実行結果:

よく見るとわかります。 fib 関数は実際にはフィボナッチ数列の計算ルールを定義しており、最初の要素から開始して後続の要素を計算できます。このロジックは実際にはジェネレーターと非常によく似ています。

言い換えれば、上記の関数はジェネレーターまであと 1 ステップです。 fib 関数をジェネレーターに変えるには、print(b) を変更して b を生成します:


実行結果:

上記の fib の例では、ループ中にそれを呼び出し続けます。中断し続けます。もちろん、ループを終了するにはループの条件を設定する必要があります。そうしないと、無限の数がリストされます。同様に、関数をジェネレーターに変更した後、基本的に次の戻り値を取得するために next() を使用することはありませんが、for ループを直接使用して反復処理します。

実行結果:

for ループを使用してジェネレーターを実行したところ、ジェネレーターの return ステートメントの戻り値を取得できないことがわかりました。戻り値を取得したい場合は、StopIteration エラーをキャプチャする必要があります。戻り値は、StopIteration の値に含まれています:


実行結果:

3.send

例: yield が実行されると、gen 関数は一時的に保存され、i の値を返します。temp は次回 c.send("python") によって送信された値を受け取ります。これは c.next と同等です。 () c.send(None)

next関数を使用


実行結果:

__next__()メソッドを使用


実行結果:

送信を使用する

実行結果:

4. マルチタスクの実装

マルチタスクをシミュレートする方法の 1 つ: コルーチン


実行結果:

概要

ジェネレーターはこのような function は、最後に返されたときの関数本体内の位置を記憶します。ジェネレーター関数の 2 番目 (または n 番目) の呼び出しは、関数の途中にジャンプし、すべてのローカル変数は前の呼び出しから変更されないままになります。

ジェネレーターはデータの状態を「記憶」するだけではなく、フロー制御構造内の位置も「記憶」します (命令型プログラミングでは、この構造は単なるデータ値ではありません)。

ジェネレーターの特徴:

1. メモリを節約します。

2. 次の呼び出しに反復するときに、使用されるパラメーターは最初から保持されているものです。つまり、すべての関数呼び出しのパラメーターは次のとおりです。新しく作成されるのではなく、最初に呼び出されたときにすべてが保持されます

5. Iterator

反復は、コレクション要素にアクセスする方法です。イテレータは、トラバースの位置を記憶するオブジェクトです。イテレータ オブジェクトは、コレクションの最初の要素からアクセスを開始し、すべての要素がアクセスされるまでアクセスします。イテレータは前方にのみ進むことができ、後方には進むことができません。

1. 反復可能なオブジェクト

for ループに直接作用するデータ型は次のとおりです。

1 つのタイプは list、tuple、dict、set、str などのコレクション データ型です。ジェネレーター (ジェネレーターおよび yield 付きジェネレーター関数を含む)。

for ループで直接使用できるこれらのオブジェクトは、まとめて反復可能オブジェクト (Iterable) と呼ばれます。

2. 反復可能かどうかを判断する

isinstance() を使用して、オブジェクトが Iterable オブジェクトであるかどうかを判断できます:

実行結果:
ジェネレーターは、 for ループですが、使用することもできます。 next() 関数は、最終的に次の値を返せないことを示す StopIteration エラーがスローされるまで、次の値を呼び出して返し続けます。

3. イテレータ

next() 関数で呼び出すことができ、継続的に次の値を返すオブジェクトをイテレータと呼びます。

操作結果:
4.iter() function
Generatorsは全てIteratorオブジェクトですが、list、dict、strはIterableですがIteratorではありません。

list、dict、str およびその他の Iterable を Iterator に変えるには、 iter() 関数を使用できます:

実行結果:

概要

・forループで使用できるすべてのオブジェクトはIterable型です。

・next()関数で使用できるすべてのオブジェクトはIterator型です

・リスト、 dict、str などは Iterable ですが、Iterator ではありませんが、 iter() 関数を通じて Iterator オブジェクトを取得できます。

· 目的は、コレクションを使用するときに占有されるコンテンツを減らすことです。

6. クロージャ

1. 関数リファレンス


イラスト:

2. クロージャとは

実行結果:

3. クロージャの実際の例を見てみましょう:
実行結果:


この例では、関数行と変数 a と b がクロージャを形成します。クロージャを作成するとき、line_conf のパラメータ a および b を通じてこれら 2 つの変数の値を指定します。このようにして、関数の最終形式 (y = x + 1 および y = 4x + 5) を決定します。パラメータ a と b を変換するだけで、異なる直線式関数が得られます。このことから、クロージャにはコードの再利用性を向上させる効果もあることがわかります。
クロージャがない場合、直線関数を作成するたびに a、b、x を指定する必要があります。この方法では、より多くのパラメーターを渡す必要があるため、コードの移植性も低下します。学習プロセス中に問題が発生した場合、または学習リソースを入手したい場合は、学習交換グループ
626062078 への参加を歓迎します。一緒に Python を学びましょう。 !

以上がPython - ジェネレーターの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。