Pythonで大量データや効率的な処理が求められる場面で欠かせないのが「イテレータ」と「ジェネレータ」です。本記事では、両者の仕組み・違い・具体的な使い方・活用例まで、初心者にも分かりやすく解説します。
「for文の裏側で何が起きているのか」「メモリ効率を高めたい」「無限データを扱いたい」といった疑問や課題を解決できる内容です。
イテレータとは?Pythonの反復処理の基礎
イテレータは、リストやタプルなどのコレクションから要素を「1つずつ順番に取り出す」ためのオブジェクトです。
Pythonのイテレータは、__iter__()
と__next__()
という2つのメソッドを持ち、iter()
で作成し、next()
で次の要素を取得します。
イテレータの基本例
numbers = [1, 2, 3, 4, 5]
iterator = iter(numbers)
print(next(iterator)) # 1
print(next(iterator)) # 2
iter()
でイテレータを作成next()
で順次要素を取得- 取得しきると
StopIteration
例外が発生
カスタムイテレータの作成
独自のイテレータは、__iter__()
と__next__()
を実装したクラスで作成できます。
class MyIterator:
def __init__(self, max_value):
self.max_value = max_value
self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current < self.max_value:
self.current += 1
return self.current - 1
else:
raise StopIteration
ジェネレータとは?イテレータを簡単に作る仕組み
ジェネレータは、「必要な時にだけ次の値を生成する」特別なイテレータです。
最大の特徴は、yield
キーワードを使うことで、複雑なイテレータを簡潔に実装できる点にあります。
ジェネレータのイメージ
- 本を1ページずつ読むように、必要な時だけ新しいデータを生成
- 全データを一度にメモリに持たず、メモリ効率が高い
- 一度生成した値は再取得できない(ステートフル)
ジェネレータ関数の例
def count_up():
x = 0
while True:
yield x
x += 1
gen = count_up()
print(next(gen)) # 0
print(next(gen)) # 1
yield
で値を返し、関数の実行を一時停止- 次に
next()
されると、停止した場所から再開
ジェネレータ式
リスト内包表記に似た構文で、さらに簡潔にジェネレータを作れます。
numbers = (i for i in range(10) if i % 2 == 0)
for n in numbers:
print(n)
イテレータとジェネレータの違い・比較
項目 | イテレータ(Iterator) | ジェネレータ(Generator) |
---|---|---|
実装方法 | クラスで__iter__ と__next__ を実装 | 関数でyield を使う/ジェネレータ式 |
コード量 | 多い(状態管理が必要) | 少ない(簡潔に書ける) |
メモリ効率 | 実装次第 | 高い(遅延評価・必要な時だけ生成) |
再利用性 | 状態を戻せば再利用可能 | 一度使い切ると再利用不可 |
典型的用途 | 独自の反復処理ロジックが必要な場合 | 大量データや無限データ、メモリ節約したい場合 |
ジェネレータ・イテレータの活用シーン
- 大量データの逐次処理:全件を一度にリスト化せず、1件ずつ処理することでメモリ節約
- 無限シーケンス:フィボナッチ数列やカウントアップなど、終わりのないデータ生成
- ファイルの1行ずつ処理:巨大なファイルも効率的に処理可能
- パフォーマンス最適化:リスト内包表記の代わりにジェネレータ式を使うことで、メモリ消費を抑制
まとめ:Pythonで効率的な反復処理を実現しよう
- イテレータは「1つずつ要素を取り出す仕組み」
- ジェネレータは「イテレータを簡単に書けて、必要な時だけ値を生成」
- 両者を使い分けることで、Pythonのパフォーマンスと可読性を大幅に向上できる
大量データや無限データ、メモリ効率に悩んだら、ぜひジェネレータ・イテレータを活用してみてください。
コメント