Python3 イテレータとジェネレータ


イテレータ

イテレーションは Python の最も強力な機能の一つであり、コレクションの要素にアクセスする方法です。

イテレータは、走査位置を記憶できるオブジェクトです。

イテレータオブジェクトはコレクションの最初の要素からアクセスを開始し、すべての要素にアクセスし終えると終了します。イテレータは前方にのみ進み、後戻りはできません。

イテレータには2つの基本的なメソッドがあります:iter()とnext()。

文字列、リスト、タプルオブジェクトはすべて、イテレータの作成に使用できます:

例(Python 3.0+)

>>> list=[1,2,3,4]
>>> it = iter(list)    # イテレータオブジェクトを作成
>>> print (next(it))   # イテレータの次の要素を出力
1
>>> print (next(it))
2
>>>

イテレータオブジェクトは、通常の for 文を使用して走査できます:

例(Python 3.0+)

#!/usr/bin/python3 list=[1,2,3,4] it = iter(list) # イテレータオブジェクトを作成 for x in it: print (x, end=" ")

上記のプログラムを実行すると、出力結果は次のようになります:

1 2 3 4

next() 関数を使用することもできます:

例(Python 3.0+)

#!/usr/bin/python3 import sys # sys モジュールをインポート list=[1,2,3,4] it = iter(list) # イテレータオブジェクトを作成 while True: try: print (next(it)) except StopIteration: sys.exit()

上記のプログラムを実行すると、出力結果は次のようになります:

1
2
3
4

イテレータを作成する

クラスをイテレータとして使用するには、クラス内で __iter__() と __next__() の2つのメソッドを実装する必要があります。

すでにオブジェクト指向プログラミングを理解しているなら、クラスにはコンストラクタがあり、Python のコンストラクタは __init__() であり、オブジェクトの初期化時に実行されることを知っているでしょう。

詳細は次を参照してください:Python3 オブジェクト指向

__iter__() メソッドは特別なイテレータオブジェクトを返します。このイテレータオブジェクトは __next__() メソッドを実装し、StopIteration 例外によってイテレーションの完了を通知します。

__next__() メソッド(Python 2 では next())は、次のイテレータオブジェクトを返します。

数値を返すイテレータを作成します。初期値は 1 で、1 ずつ増加します:

例(Python 3.0+)

class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): x = self.a self.a += 1 return x myclass = MyNumbers() myiter = iter(myclass) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter))

実行すると出力結果は次のようになります:

1
2
3
4
5

StopIteration

StopIteration 例外はイテレーションの完了を示すために使用され、無限ループを防ぎます。__next__() メソッド内で、指定した反復回数を完了した後に StopIteration 例外を発生させてイテレーションを終了するように設定できます。

20回の反復後に実行を停止します:

例(Python 3.0+)

class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): if self.a <= 20: x = self.a self.a += 1 return x else: raise StopIteration myclass = MyNumbers() myiter = iter(myclass) for x in myiter: print(x)

実行すると出力結果は次のようになります:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

ジェネレータ

Python では、yield を使用したyield関数はジェネレータ(generator)と呼ばれます。

yieldyield はキーワードであり、ジェネレータ関数を定義するために使用されます。ジェネレータ関数は特別な関数で、反復処理中に値を段階的に生成でき、すべての結果を一度に返すのではありません。

通常の関数とは異なり、ジェネレータはイテレータを返す関数であり、反復操作にのみ使用できます。より簡単に理解すると、ジェネレータはイテレータそのものです。

ジェネレータ関数内で yield 文をyield使用すると、関数の実行は一時停止し、yield のyield後ろの式が現在の反復の値として返されます。

次に、ジェネレータの next()next()メソッドまたは for ループをfor使用して反復すると、関数は前回中断した場所から再開し、再び yield 文にyield遭遇するまで実行を続けます。こうして、ジェネレータ関数は値を段階的に生成でき、すべての結果を一度に計算して返す必要はありません。

ジェネレータ関数を呼び出すと、返されるのはイテレータオブジェクトです。

以下は、ジェネレータ関数の使用例を示す簡単な例です:

例

def countdown(n): while n > 0: yield n n -= 1 # ジェネレータオブジェクトを作成 generator = countdown(5) # ジェネレータを反復して値を取得 print(next(generator)) # 出力: 5 print(next(generator)) # 出力: 4 print(next(generator)) # 出力: 3 # for ループを使用してジェネレータを反復 for value in generator: print(value) # 出力: 2 1

上記の例では、countdowncountdown 関数はジェネレータ関数です。yield 文を使用して、n から 1 までの逆順の数値を段階的に生成します。yield 文を呼び出すたびに、関数は現在の逆順の値を返し、次回の呼び出しでは前回中断した場所から実行を続けます。

ジェネレータオブジェクトを作成し、next() 関数または for ループを使用してジェネレータを反復することで、ジェネレータ関数が生成する値を段階的に取得できます。この例では、最初に next() 関数を使用して最初の3つの逆順の値を取得し、次に for ループで残りの2つの逆順の値を取得しています。

ジェネレータ関数の利点は、必要に応じて値を生成できるため、一度に大量のデータを生成して大量のメモリを消費することを避けられることです。さらに、ジェネレータは for ループなどの他の反復ツールとシームレスに連携でき、簡潔で効率的な反復方法を提供します。

上記のプログラムを実行すると、出力結果は次のようになります:

5
4
3
2
1

以下の例では、yield を使用してフィボナッチ数列を実装しています:

例(Python 3.0+)

#!/usr/bin/python3 import sys def fibonacci(n): # ジェネレータ関数 - フィボナッチ a, b, counter = 0, 1, 0 while True: if (counter > n): return yield a a, b = b, a + b counter += 1 f = fibonacci(10) # f はジェネレータによって返されるイテレータです while True: try: print (next(f), end=" ") except StopIteration: sys.exit()

上記のプログラムを実行すると、出力結果は次のようになります:

0 1 1 2 3 5 8 13 21 34 55
その他の拡張