[ 参照リンク:Pythonのジェネレーター](https://www.imangodoc.com/266.html)
反復の概念
前の出力の結果が次の入力の初期値です。繰り返されるプロセスは反復と呼ばれます。各反復は1回の反復であり、各反復の結果は次の反復の初期値です。
反復とは
コレクション要素にアクセスする1つの方法である、forループを通過できるオブジェクトは、反復可能オブジェクトと呼ばれます。数値型は反復可能ではありません。
オブジェクトが反復可能かどうかを判別します。isinstance()それが反復可能かどうかを判別します(反復可能オブジェクト)
from collections.abc import Iterable
print(isinstance([1,2,3,4],Iterable))
反復可能なオブジェクトはTrueを返しますか
反復可能なオブジェクトではありませんがFalseを返します
反復可能なオブジェクト
組み込みのiterメソッドは反復可能なオブジェクトです。 Listは反復可能なオブジェクトであり、dictは反復可能なオブジェクトであり、setも反復可能なオブジェクトです。
イテレーター
なぜイテレーターがあるのですか?インデックスのないデータタイプの場合、インデックスに依存しない反復メソッドを提供する必要があります。
Iteratorの定義:Iterator:iterableオブジェクトはiterメソッドを実行し、得られた結果はiteratorです。iteratorオブジェクトには次のメソッドがあります。
これはステートフルオブジェクトです。next()メソッドを呼び出すと、コンテナ内の次の値を返すことができます。iterメソッドとnext()メソッドを実装するオブジェクトはすべてイテレータです。Iterはイテレータ自体を返します。nextコンテナ内の次の値を返します。コンテナ内にこれ以上要素がない場合は、StopIteration例外をスローします。
イテレーターのトラバーサルループ:
class MyIterator(object):
def init(self,list):
self.list=list
self.xiabiao=0
def __iter __(self):#イテレーターを取得します。それ自体はイテレーターなので、自分自身を返します。
return self
def __next __(self):#イテレーターで次のデータを取得します
if self.xiabiao < len(slef.list):
item=self.list[self.xiabiao]
self.xiabiao += 1
return item
else:
StopIteration#throwing停止反復例外を発生させます
a=[11,22,33,44,55]
my=MyIterator(a)
for i in my:
print(i)
for ... in ...ループの本質:最初にiter()を介して反復可能オブジェクトの反復子を取得し、次に取得した反復子でnext()メソッドを継続的に使用して次の値を取得し、StopIterationが発生したときに変数に割り当てます。ループの終わり
while True:
try:
print(next( ))
except StopIteration:
break
イテレーターのアプリケーションシナリオ:Fibonacciシーケンス
class Fei(object):
def init(self,n):
self.n=n
self.weizhi = 0レコードの場所
self.num1 = 0は初期変数を定義します
self.num2=1
def __iter __(self):イテレーターを取得します。このクラス自体はイテレーターです。それ自体を返します。
return self
def __next __(self):イテレーターで次のデータを取得します
if self.weizhi < self.n:
num=self.num1
self.num1,self.num2=self.num2,self.num1+self.num2
self.weizhi += 1
return num
else:
raise StopIteration
fei=Fei(10)
for i in fei:
print(i)
イテレーターデータを表示する3つの方法:for、list、tuple
for i in fei:
print(fei)
print(list(fei))
print(tuple(fei))
発生器
ジェネレーターは特別なイテレーターであり、その実装はよりシンプルでエレガントであり、yieldはジェネレーターのnext()メソッドの鍵です。ジェネレーター実行の一時停止および再開ポイントとして機能し、yield式に値を割り当てることができ、yield式の値を返すこともできます。言い換えると、yieldは構文上の砂糖であり、内部実装はイテレータープロトコルをサポートし、内部yieldは一時停止状態と継続状態を維持する状態マシンです。ジェネレータはデータタイプとして理解できます。このデータタイプは自動的にイテレータプロトコルを実装します(他のデータタイプは独自の組み込みiterメソッドを呼び出す必要があります)。Pythonでは、計算中のループのメカニズムはジェネレータと呼ばれます。
収量の関数:
iterとnextreturnが値を1回だけ返すことができ、関数が終了し、yieldが複数の値を返すことができ、各returnが関数を一時停止し、次の次が最後の一時停止位置から実行を継続して現在を保存するという関数のカプセル化と同等です実行状態、実行の一時停止、yieldキーワードの後の式の値を戻り値として返します。これは、戻り値として理解できます。
ジェネレーターの役割
リストを生成することで直接リストを作成できますが、メモリの制限により、リストの容量は確実に制限されます。さらに、100万個の要素のリストを作成すると、多くのストレージスペースが必要になるだけでなく、最初のいくつかの要素にアクセスするだけでよい場合、後者の要素のほとんどが占めるスペースが無駄になります。したがって、リスト要素が特定のアルゴリズムに従って計算できる場合、ループ内の後続の要素を計算し続けることができますか?これにより、完全なリストを作成する必要がなくなり、多くのスペースを節約できます。 Pythonでは、whileループを計算するこのメカニズムは、generator:generatorと呼ばれます。
ジェネレーターのしくみ
ジェネレーターは、最後に戻ったときに関数の本体内での位置を記憶する関数です。ジェネレーター関数への2番目(またはn番目)の呼び出しは関数の中央にジャンプし、最後の呼び出しのすべてのローカル変数は変更されません。ジェネレータは、データの状態を「記憶」するだけでなく、フロー制御構造内の位置も「記憶」します。ジェネレータは関数であり、関数のパラメータは保持されます。次の呼び出しに繰り返すとき、使用されるパラメーターはすべて初めて予約されます。つまり、すべての関数呼び出しのパラメーターは、新しく作成されるのではなく、最初の呼び出しのために予約されます。
イールドジェネレーターの操作メカニズムはPythonであり、イールドはそのようなジェネレーターです。
ジェネレーターに数値を要求すると、ジェネレーターはyieldステートメントが表示されるまで実行され、ジェネレーターはyieldパラメーターを提供します。その後、ジェネレーターは実行を継続しません。次のカウントを要求すると、yieldステートメントが表示されるまで前の状態から実行され、パラメーターが指定されてから停止します。そのため、Pythonで繰り返し、関数を定義してyieldキーワードを使用すると、この関数はジェネレーターになります。その実行は他の通常の関数とは異なります。関数は、通常使用するものではなく、オブジェクトを返します。 returnステートメントと同様に、結果値を取得できます。値を取得する場合は、next()関数を呼び出す必要があります。イテレーターのnext関数を呼び出すたびに、ジェネレーター関数はyieldポイントまで実行され、yield後に値を返し、このポイントで一時停止します。すべての状態が維持されます。次の関数が次回呼び出されるまで、または例外ループの終了が発生するまで。
なぜジェネレーターはイテレーターなのですか?オブジェクトがイテレーターであるかどうかを判断するためのPythonの標準は、オブジェクトがイテレータープロトコルに準拠しているかどうかを確認することであり、オブジェクトがイテレータープロトコルに準拠しているかどうかを判断することは、主に2つの側面に依存します。
オブジェクトは最初にiterメソッドとnextメソッドを実装する必要があり、次にiterメソッドはそれ自体を返す必要があります
ジェネレーターは、これら2つの条件を満たしています(ジェネレーターを自分で作成してから、ジェネレーターのこれら2つのメソッドを呼び出して試すことができます)。私たちはしばしば別の概念に遭遇します:反復可能なオブジェクト。反復可能オブジェクトは反復可能オブジェクトであり、反復可能オブジェクトは、このオブジェクトから反復子を取得できることを意味します。 Pythonでは、iterメソッドはこれを実現するのに役立ちます。つまり、反復可能オブジェクトと反復子は、iter(iterable)-> iteratorという関係を満たします。
Pythonでは、listは反復可能なオブジェクトであるため、次のようなコードを作成することがよくあります。
l = [1, 2, 3]
for element in l:
print(element)
しかし、なぜ私たちがこのように書くことができるのか疑問に思ったことはありますか?なぜC言語では、配列要素にアクセスするときにインデックスを渡さなければならないのですか?
理由:listは反復可能なオブジェクトであるため、Pythonで…を使用すると、Pythonは反復子オブジェクトを生成します。前述のように、反復子はデータストリームであり、データを生成できます。常にそこからデータを取得します。コード内のインデックスを維持する必要がなくても、Pythonはイテレーターを介してこれを実行してくれます。
ジェネレーターを作成します。リスト内包表記の角括弧を括弧に変更します。
g=(i for i in range(1,11))
print(g)
歩留まりを使用してFibonacciシーケンスを構築します
def fei(n):
num1,num2=0,1
weizhi=0
while weizhi < n :
num=num1
num1,num2=num2,num1+num2
weizhi += 1
yield num
print(list(fei(10)))
ウェイクアップジェネレータ:send()、next()、__ next __()
send( )
ret=fei(10)
a=ret.send(None)
print(a)
next( )
ret=fei(10)
while True:
try:
print(next(ret))
except StopIteration:
break
ジェネレーターとイテレーターの違い
ジェネレーターを使用する場合は関数を作成し、イテレーターを使用する場合は組み込み関数iter()およびnext()を使用します。ジェネレーターでは、キーワード「yield」を使用して、一度にオブジェクトを生成/返します。ジェネレーターにある「yield」ステートメントの数をカスタマイズできます。 'yield'がループを一時停止するたびに、ジェネレーターはローカル変数の状態を保存します。イテレーターはローカル変数を使用せず、イテレーションに必要なのはイテラブルオブジェクトのみです。クラスを使用して独自のイテレーターを実装しますが、ジェネレーターは実装しません。ジェネレーターは高速に実行され、構文は簡潔で単純です。イテレータはより多くのメモリを節約できます。
Recommended Posts