Pythonイテレータ完全ガイド:仕組みと自作方法
Pythonイテレータ
Pythonイテレータの仕組み、forループやnext()関数での走査、イテレータプロトコルを使ったカスタム/無限イテレータの作成方法を学びます。
動画:Pythonイテレータ
Pythonにおけるイテレータ
イテレータはPythonに遍在します。forループ、リスト内包表記、ジェネレータ、多くの組み込みデータ構造の基盤となっており、しばしば舞台裏で働きます。
イテレータは単にデータを1要素ずつ生成するオブジェクトです。Pythonでは__iter__()と__next__()メソッドを実装したオブジェクトをイテレータと見なします。
イテレータを提供できるオブジェクトをイテラブルと呼びます。リスト、タプル、文字列、辞書などほとんどの組み込みコンテナはイテラブルです。組み込みiter()関数はオブジェクトの__iter__()メソッドを呼んでイテレータを取得します。
イテレータを通したイテレーション
next()関数でイテレータを手動で進められます。イテレータが尽きるとStopIterationが発生します。
# リスト定義
my_list = [4, 7, 0, 3]
# iter()でイテレータ取得
my_iter = iter(my_list)
# next()でイテレーション
# 出力: 4
print(next(my_iter))
# 出力: 7
print(next(my_iter))
# next(obj) == obj.__next__()
# 出力: 0
print(my_iter.__next__())
# 出力: 3
print(my_iter.__next__())
# 要素なしでエラー
next(my_iter)
出力
4 7 0 3 Traceback (most recent call last): File "<string>", line 24, in <module> next(my_iter) StopIteration
より自然なイテレーションはforループで、イテレータライフサイクルを自動処理します。
>>> for element in my_list:
... print(element)
... 4 7 0 3
forループがイテレータでどう動作するか
forループは内部的に以下に変換されます:
for element in iterable:
# elementで何かする
これは以下のロジックと等価:
# イテラブルからイテレータオブジェクト作成
iter_obj = iter(iterable)
# 無限ループ
while True:
try:
# 次のアイテム取得
element = next(iter_obj)
# elementで何かする
except StopIteration:
# StopIteration発生でループ脱出
break
これはforループが本質的にイテレータプロトコルとStopIteration例外に依存する無限ループであることを示しています。
カスタムイテレータの構築
スクラッチからイテレータを作成するのは簡単:__iter__()でイテレータインスタンス(多くの場合self)を返し、__next__()で次の値を生成、終了時にStopIterationを発生させます。
以下はユーザー指定最大指数までの2の累乗を生成する例です。
class PowTwo:
"""2の累乗を生成するイテレータ。"""
def __init__(self, max=0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
result = 2 ** self.n
self.n += 1
return result
else:
raise StopIteration
# オブジェクト作成
numbers = PowTwo(3)
# オブジェクトからイテラブル作成
i = iter(numbers)
# nextで次のイテレータ要素へ
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
出力
1 2 4 8 Traceback (most recent call last): File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module> print(next(i)) File "<string>", line 18, in __next__ raise StopIteration StopIteration
カスタムイテレータでのforループ使用も同様にシンプル:
>>> for i in PowTwo(5):
... print(i)
... 1 2 4 8 16 32
Python無限イテレータ
イテレータは無制限でもよいです。組み込みiter()は呼び出し可能オブジェクトとセンチネル値を受け取り:関数を繰り返し呼び、戻り値がセンチネルと等しくなるまで継続。例:
>>> int()
0
>>> inf = iter(int, 1)
>>> next(inf)
0
>>> next(inf)
0
int()は常に0を返すため、iter(int, 1)はセンチネルを永遠に見ず、無限イテレータを生成します。
独自の無限イテレータも作成可能、例えばすべての奇数を生成するもの:
class InfIter:
"""連続する奇数を返す無限イテレータ。"""
def __iter__(self):
self.num = 1
return self
def __next__(self):
num = self.num
self.num += 2
return num
実行例:
>>> a = iter(InfIter())
>>> next(a)
1
>>> next(a)
3
>>> next(a)
5
>>> next(a)
7
無限イテレータ使用時は常に終了条件を設け、無限ループを避けてください。
イテレータはオンデマンドでアイテム生成するためメモリ効率的です。理論上、すべての奇数のような無限シーケンスを全体を格納せず生成可能です。
よりシンプルなイテレータ作成法についてはPythonジェネレータ(yield使用)を参照。
Python
- Python データ型マスター: 実践ガイド
- Python 演算子完全マスター: 包括的ガイド
- Python pass文完全マスター: 実践ガイド
- Python 関数引数完全マスター: 位置引数・キーワード引数・デフォルト引数
- Python辞書完全ガイド:作成、操作、高度なテクニック
- Pythonクロージャ解説:ネスト関数が変数を捕捉する仕組み
- Python datetimeマスター:日付・時刻・タイムゾーン実践ガイド
- Pythonのtime.sleep()をマスター:ベストプラクティス、マルチスレッド、実例
- Python 概要:高水準、読みやすい、インタラクティブ、オブジェクト指向
- Python 数値型完全ガイド:不変な数値データ型の理解と活用
- Python 文字列完全マスター:作成、アクセス、操作のすべて