__iter__ および __next__ という名前のクラス メソッドを使用してカスタム イテレータを作成する方法。Python のジェネレーターを使用してカスタム イテレーターを作成する方法も学習します。
クラスメソッド __iter__ および __next__ を使用してカスタム反復子を作成する
ここでイテレータと言うと、その名前が示すように、反復するために使用されます。
C、C++、Java などの言語を使用している場合は、++ という共通の概念があります。反復について話している間に、for ループという別の概念が知られています。
5 つの要素を含むリストがあるとします。ループを使用すると、最初の要素から最後の要素まで繰り返すことができます。
このようにして、値をインデックス番号とともに 1 つずつ出力する場合に、いくつかの値を含むリストが得られます。
インデックス 0 を渡すと、最初の要素 2 が返されます。インデックス値 1 を使用すると、2 番目の要素 5 が得られます。
Numbers=[2,5,10,3,1]
print(Numbers[0])
print(Numbers[1])
出力:
2
5
値を出力するもう 1 つの方法は、ループを使用することです。リストを反復処理して、すべての値を出力できます。
Numbers=[2,5,10,3,1]
for i in Numbers:
print(i)
出力:
2
5
10
3
1
ここで、イテレータを使用するという別の方法があります。一般に、反復子はループの舞台裏で動作します。
リストをイテレータに変える iter() 関数を使用してイテレータを理解します。このイテレータはすべての値を提供するわけではなく、一度に 1 つの値のみを提供します。
Numbers=[2,5,10,3,1]
ITR=iter(Numbers)
print(ITR)
イテレータオブジェクトを出力していることがわかります。
<list_iterator object at 0x000001FEDCFF7310>
ただし、値が必要な場合は、ITR.__next__()
組み込みメソッドである set を使用できます。特定のオブジェクトに対して初めてメソッドが呼び出されたときに__next__()
最初の値が得られます。これはインデックス付きの値を使用するのと同じ方法ですが、インデックス付きの値を使用する必要がないという利点があります。
umbers=[2,5,10,3,1]
ITR=iter(Numbers)
print(ITR.__next__())
出力:
2
次の実行行で実行するとITR.__next__()
、次の値が得られます。バックグラウンドではイテレータには複数の値があるため、 __next__() メソッドを呼び出すと、値が取得されます。
また、__next__() を呼び出すと、i の最後の値がわかります。つまり、最後の値の状態が保持されます。これがイテレータの利点であり、関数を再度呼び出すと、古い値が保持されます。
クラスを使用してイテレータを作成できます。このクラスを使用すると、最初の 10 個の値を個別に出力できます。
この目的のために、TopValues というクラスを用意し、このクラスでカウンターを指定します。
このために、__init__ 関数を使用し、カウンター変数 self.N=1 を定義します。明らかに、カウンターは 1 から初期化されます。カスタム反復子を作成するには 2 つの重要なメソッドが必要です。
最初のメソッドは iter() メソッドでイテレータ オブジェクトを提供し、次に next() メソッドは次の値またはオブジェクトを提供します。__next__ メソッドでは、self.N を返す代わりに、VALUE という変数を使用して self.N を設定し、次の行で self.N を 1 にインクリメントします。
こうすることで、次の反復ごとにインクリメントされ、self.N ではなく VALUE が返されます。これは、self.N が次の反復でインクリメントされるためです。
class TopValues:
def __init__(self):
self.N=1
def __iter__(self):
return self
def __next__(self):
VALUE=self.N
self.N+=1
return VALUE
これでイテレータの準備が整い、TopValues クラスのオブジェクトを作成できるようになりました。通常、反復子がある場合はループを使用できるため、ループを使用しましょう。
T_Val=TopValues()
for i in T_Val:
print(i)
このコードを実行すると、数千の値が得られます。
1
2
3
4
5
....
1000
何が起こっているのか理解してみましょう。イテレータが機能するかどうかを確認するには、__next__() を使用します。
print(T_Val.__next__())
この行では最初の反復値 1 が出力されますが、ループの何が問題になっているのでしょうか? 問題は、このループが開始点から終了点まで続くことです。終了点は 10 であると想定していますが、どこで停止すべきかについては言及していません。
ループを使用すると、next() 関数が呼び出されます。これがその仕組みです。for ループは内部で next() 関数を使用するため、この next() 関数を繰り返し呼び出します。
__next__ メソッド内で条件を適用する必要があります。
else ブロックも設定する必要があります。このブロック内で例外を発生させます。それ以外の場合、10 個の値を出力した後、ループは None を出力します。
class TopValues:
def __init__(self):
self.N=1
def __iter__(self):
return self
def __next__(self):
if self.N<=10:
VALUE=self.N
self.N+=1
return VALUE
else:
raise StopIteration
T_Val=TopValues()
for i in T_Val:
print(i)
出力:
1
2
3
4
5
6
7
8
9
10
ジェネレーターを使用してカスタム反復子を作成する
次に、同じことを行うジェネレーター関数を作成してみましょう。ジェネレーターは __iter__() メソッドと __next__() メソッドを処理するため、はるかに単純です。
Our_Gen() というジェネレーター関数を作成しようとすると、この関数にパラメーターを渡します。
リストをループしているため、項目は一度に 1 つずつ生成されます。また、ループする項目がなくなったときに自動的に処理し、例外を発生させて反復を停止します。
ここで、Our_Gen() 関数をループしているので、一度に 1 つの項目が出力されるはずです。これを実行すると、一度に 1 つずつ取得されることがわかります。
def Our_Gen(n_list):
for i in n_list:
yield i
Func=Our_Gen([2,5,10,3,1])
for i in Func:
print(i)
出力:
2
5
10
3
1
next() 関数がまだ動作していることを確認するためです。実行後、5 つの要素が取得され、反復を停止する例外が発生します。
#Python小白学习交流群:711312441
def Our_Gen(n_list):
for i in n_list:
yield i
Func=Our_Gen([2,5,10,3,1])
print(Func.__next__())
print(Func.__next__())
print(Func.__next__())
print(Func.__next__())
print(Func.__next__())
print(Func.__next__())
出力:
2
5
10
3
1
Traceback (most recent call last):
File "c:UsersDellDesktopdemodemo.py", line 56, in <module>
print(Func.__next__())
StopIteration
ジェネレーターはクラスよりも簡単に作成できます。ただし、ユースケースによっては、クラス内で __iter__() メソッドと __next__() メソッドを実行する方法を知る必要がある場合があります。
カスタム イテレータの作成について詳しくは、こちらをご覧ください。