Pythonのジェネレータ式、イテレーター、イテラブルといった基本的な用語や概念について、まとめました。
はじめに
Pythonでプログラミングをしていると、「反復処理(反復=繰り返し)」、「イテレータ」、「イテラブル」、「ジェネレータ」といった言葉を耳にすることが多くなります。
これらの概念は、「大量のデータを効率よく扱う」、「必要なときに必要な分だけ計算する」 というPythonの強みを引き出すために重要な要素です。
以下では、これらの用語を整理し、簡単な例とともに解説していきます。
イテラブル(Iterable)とは?
イテラブル とは、「繰り返し処理が可能なオブジェクト」のことです。
具体例としては、list
、tuple
、set
、dict
、str
など、for
ループで回せるものはすべてイテラブルです。
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
ここで fruits
はイテラブルです。for
ループによって、"apple"
, "banana"
, "cherry"
の要素が順番に取り出され、出力されます。
ポイント:
- イテラブルは「forで回せるもの」と覚えると簡単です。
イテレーター(Iterator)とは?
イテレーター は、イテラブルから要素を一つずつ取り出すための「仕組み」を備えたオブジェクトです。
イテレーターは、next()
関数を使って要素を順番に取り出すことができます。
イテラブルからイテレーターを作るには、iter()
関数を使います。
fruits = ["apple", "banana", "cherry"]
it = iter(fruits) # イテレーターを作成
print(next(it)) # "apple"
print(next(it)) # "banana"
print(next(it)) # "cherry"
# print(next(it)) をもう一度呼ぶとStopIterationエラーが起きる
ポイント:
- イテレーターは「一方向に一度きり進めるデータ供給器」のようなイメージ。
-
next()
で要素を一つずつ取り出し、最後まで行くとストップします。
ジェネレータ(Generator)とは?
ジェネレータ は、関数や式から「必要なときに必要な分だけ要素を生成する(惰性評価)」仕組みを持つイテレーターの一種です。
ジェネレータ関数
yield
キーワードを使った関数定義がジェネレータ関数です。yield
は関数の処理を一時停止し、値を返しつつ関数の状態を保持します。次にnext()
を呼ぶと、前回の続きから処理が進みます。
def count_up_to(n):
count = 1
while count <= n:
yield count
count += 1
gen = count_up_to(3)
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# 次のnextでStopIteration
ジェネレータ式(Generator Expression)
ジェネレータ式はリスト内包表記と似ていますが、[]
の代わりに ()
を使うか、関数引数として書くことで、リストを作らずに要素を一つずつ生成するイテレーターを返します。
# リスト内包表記:全要素を一度に生成する
lst = [x * 2 for x in range(5)]
print(lst) # [0, 2, 4, 6, 8]
# ジェネレータ式:必要なときだけ要素を生成する
gen = (x * 2 for x in range(5))
print(next(gen)) # 0
print(next(gen)) # 2
print(next(gen)) # 4
ポイント:
- リスト内包表記はすぐに全要素をリストに格納する。
- ジェネレータ式は必要なときに要素を生成するため、メモリ効率が良い。
なぜジェネレータやイテレーターが重要なのか?
-
メモリ効率:
大量のデータを扱うとき、すべてをリストに格納するとメモリを圧迫します。ジェネレータなら、必要になった瞬間に値を計算・生成するため、巨大なリストを一度にメモリに載せる必要がありません。 -
遅延評価(Lazy Evaluation):
計算コストの高い処理や、無限に続くシーケンス(例えば一定条件が来るまでカウントアップなど)において、必要なタイミングまで計算を遅らせられます。 -
パイプライン処理:
イテレーターは、別のイテレーターへの入力として組み合わせて使うことができます。UNIXのパイプのように、データを流しながら段階的に処理することで、コードをモジュール化したり効率よくデータ処理ができます。
まとめ
-
イテラブル:
for
ループで回せるオブジェクト。(例:リスト、文字列) -
イテレーター:
iter()
で作成でき、next()
で要素を一つずつ取り出せるオブジェクト。 -
ジェネレータ:
yield
を使った関数や、( ... )
で書くジェネレータ式によって、必要な分だけ要素を惰性的に生成するイテレーター。
これらを理解しておけば、Pythonで効率的なデータ処理ができるようになります。大量のデータや無限系列など、普通のリストでは扱いにくい場面でも、ジェネレータやイテレーターを活用することでメモリ効率と柔軟性が格段に向上します。