Pythonを学んでいると必ず出てくる言葉にイテレータとジェネレータがあります。
これらはどちらもデータを順番に取り出して処理するための仕組みですが、聞いただけだと難しそうに感じる人も多いはずです。 実際、プログラミング初心者の段階ではfor文を使ってループできれば十分なのでは?と感じる方も多いでしょう。
しかし、データ量が大きくなったり、処理を効率化したいときには、このイテレータとジェネレータがとても役立ちます。
今回は、この2つの仕組みを初心者でも理解しやすいように、実際のコード例を交えながら丁寧に解説していきます。
まずはイテレータから見ていきましょう。
イテレータという言葉は聞き慣れないかもしれませんが、実は皆さんがすでに使っているfor文の裏側ではイテレータが活躍しています。
イテレータはデータを一つずつ順番に取り出すことができるオブジェクトです。
たとえばリストや文字列などをforループで回すと、Pythonが内部的にイテレータを作って、要素を1つずつ取り出しています。
自分でイテレータを作るときには、__iter__()
と__next__()
という2つの特別なメソッドを定義する必要があります。
イテレータは、以下の2つのメソッドを実装する必要があります。
以下に、カスタムイテレータを実装する例を示します。
class MyIterator:
def __init__(self, limit):
self.limit = limit # イテレータの上限値
self.current = 0 # 現在の値
def __iter__(self):
return self # イテレータ自身を返す
def __next__(self):
if self.current < self.limit:
self.current += 1
return self.current
else:
raise StopIteration # 反復の終了を通知
# MyIteratorクラスのインスタンスを生成
my_iter = MyIterator(5)
# イテレータの使用
for num in my_iter:
print(num)
以下のように出力されます。
# 出力:
1
2
3
4
5
ここで重要なのは、next()が呼ばれるたびに値を一つずつ返している点です。 そして上限に達するとStopIterationという例外を発生させ、ループを終了させます。
普段のfor文では意識する必要がありませんが、実際にはこのような仕組みが働いているのです。
次にジェネレータを見ていきましょう。
ジェネレータはイテレータをもっと簡単に作れる仕組みです。イテレータをクラスで書こうとすると、__iter__や__next__を定義する必要がありましたが、ジェネレータを使えば数行で同じ処理が実現できます。
ジェネレータのキーワードはyieldです。
通常の関数であればreturnを使って値を返しますが、ジェネレータ関数ではyieldを使って値を一つずつ返していきます。
ジェネレータは、通常の関数と同じように定義しますが、値を返す代わりに yield を使用します。 ジェネレータ関数を呼び出すと、ジェネレータオブジェクトが返されます。
イテレータと同じく「1から指定した数までを順に返す」処理をジェネレータで書いてみましょう。
def my_generator(limit):
current = 0
while current < limit:
current += 1
yield current # 値を生成し、一時停止
# ジェネレータ関数を呼び出してジェネレータオブジェクトを取得
gen = my_generator(5)
# ジェネレータの使用
for num in gen:
print(num)
以下のように出力されます。
# 出力:
1
2
3
4
5
たった数行のコードで、イテレータと同じ動作をする仕組みが作れたことが分かります。
ここで、両者の違いを分かりやすく表にまとめてみます。
特徴 | イテレータ | ジェネレータ |
---|---|---|
実装の複雑さ | クラスを定義し、__iter__と__next__を用意する必要がある | 関数内でyieldを使うだけで簡単に作れる |
メモリ効率 | 要素をすべて保持することも多く、効率が悪い場合がある | 必要になったときだけ値を生成するので効率的 |
状態の管理 | 自分で「どこまで処理したか」を記録する必要がある | Pythonが自動で状態を保持してくれる |
柔軟性 | 複雑な反復処理や特別なロジックを持つ場合 | シンプルに順番に値を返す場合や大規模データ処理 |
表で見ると、ジェネレータがシンプルで効率的に見えるかもしれません。
実際、初心者が最初に使うならジェネレータの方が分かりやすいでしょう。ただし、イテレータはより細かい制御が可能なので、ケースによってはイテレータが必要になることもあります。
Pythonのイテレータとジェネレータは、一見難しそうに思えますが「データを一つずつ順番に取り出す仕組み」と考えるとシンプルです。
大きなデータを扱うときや、効率的にループを回したいときには特に役立ちます。 最初はジェネレータを使って感覚をつかみ、必要になったときにイテレータの仕組みを使いこなせるようになると、Pythonでの開発の幅が一気に広がります。