Pythonの学習を進める中で、for文は毎日のように使いますよね。リストや文字列の要素を順番に取り出す、非常に便利な機能です。
でも、「なぜリストや文字列はfor文で順番に取り出せるんだろう?」と、その仕組みについて疑問に思ったことはありませんか?
そのカギを握るのが、今回解説する**「イテレータ」**です。
この記事では、特に初心者の方に向けて、イテレータの仕組みから作り方までを、一つひとつ丁寧に解説していきます。この記事を読み終える頃には、for文を見る目が少し変わっているはずです。
- イテレータが何なのか、基本からわかる
for文が動く本当の仕組みがわかる- 簡単なイテレータを自分で作れるようになる
それでは、さっそく見ていきましょう。
はじめに:Pythonのイテレータとは?
まずは「イテレータって一体何?」というところから始めましょう。
イテレータは「順番にデータを取り出せる道具」
イテレータをすごく簡単に言うと、**「データのかたまりから、順番に一つずつ値を取り出すための道具」**です。
next()という特別な命令を使うと、次のデータを一つ取り出すことができます。これを繰り返して、最後のデータまで取り出し終えると、「もうデータはありませんよ」と教えてくれる、とても行儀の良い道具だとイメージしてください。
「繰り返し可能なオブジェクト(Iterable)」との違いは?
イテレータの話をすると、必ず「繰り返し可能なオブジェクト(Iterable)」という言葉が出てきます。この2つはセットで覚えるのがポイントです。
- 繰り返し可能なオブジェクト(Iterable)
- 簡単に言うと**「
for文で使えるもの全般」**です。 - 私たちがよく使うリスト、タプル、文字列などがこれにあたります。
- このオブジェクトの役割は、自分自身を元にした**「イテレータを作ること」**です。
- 簡単に言うと**「
- イテレータ(Iterator)
- Iterableから作られる**「実際にデータを取り出す役目のもの」**です。
next()という命令で、データを一つずつ取り出す機能を持っています。
つまり、for文はまず、リストなどのIterableからイテレータを作り出し、そのイテレータからデータを一つずつ取り出している、という関係性になっています。
for文の裏側ではイテレータが動いている
私たちがfor num in [1, 2, 3]:と書くとき、Pythonの内部ではイテレータを使った地道な作業が行われています。
forループの正体はiter()とnext()
for文の動きを分解すると、実は以下のステップになっています。
- リスト
[1, 2, 3](Iterable)から、iter()という関数を使ってイテレータを作ります。 - ループの中で
next()という関数を使い、作られたイテレータから値を一つ取り出します。 - 取り出した値を
numという変数に入れます。 - 2と3を、イテレータが空になるまで繰り返します。
- イテレータが空になると
StopIterationという合図が出され、for文はそれを察知してループを自動で終了します。
つまりfor文は、この一連の面倒な処理を一行で書けるようにしてくれる、便利なショートカットなのです。
コードで確認!iter()とnext()の使い方
実際にfor文を使わずに、リストの要素を取り出してみましょう。
# 繰り返し可能なオブジェクト(Iterable)
my_list = ["A", "B", "C"]
# 1. iter()関数でイテレータを作る
my_iterator = iter(my_list)
print(f"イテレータの型: {type(my_iterator)}")
# イテレータの型: <class 'list_iterator'>
# 2. next()関数で値を一つずつ取り出す
print(next(my_iterator)) # 出力: A
print(next(my_iterator)) # 出力: B
print(next(my_iterator)) # 出力: C
# 3. これ以上データがないので、StopIterationというエラーが発生する
# print(next(my_iterator)) # ここを実行するとエラーになるこのように、iter()でイテレータを作り、next()で一つずつ取り出す、というfor文の裏側の動きがよく分かりますね。
Pythonでイテレータを自作する方法
イテレータの仕組みがわかったら、今度は自分で作ってみましょう。自分で作ってみるのが、理解への一番の近道です。
イテレータを作るための2つのルール
Pythonでオリジナルのイテレータを作るには、クラスに2つの特別なメソッド(お約束の関数)を定義します。
__iter__(self)メソッド- イテレータ自身を返すためのメソッドです。おまじないとして
return selfと書くことがほとんどです。
- イテレータ自身を返すためのメソッドです。おまじないとして
__next__(self)メソッドnext()関数が呼ばれたときに、次に返す値を決めるメソッドです。- もし返すデータがもう無い場合は、
StopIterationという例外を発生させてループを終わらせます。
簡単なカウンタを自作してみよう(__iter__, __next__実装)
0から指定した数まで、1ずつ数を返すだけのシンプルなイテレータSimpleCounterを作ってみます。
class SimpleCounter:
# 初期設定を行うメソッド
def __init__(self, end):
self.current = 0 # 現在の数を0で初期化
self.end = end # ゴールの数を設定
# __iter__メソッドのお約束
def __iter__(self):
return self
# next()が呼ばれたときの処理
def __next__(self):
# 現在の数がゴールより小さいかチェック
if self.current < self.end:
# 今の値をいったんvalueに保存
value = self.current
# 次のために、現在の数を1増やす
self.current += 1
# 保存しておいた値を返す
return value
else:
# ゴールに達したら、ループを終わらせる合図を送る
raise StopIteration
# 0, 1, 2, 3, 4 と5回数を返すイテレータを使ってみる
counter = SimpleCounter(5)
# 自作したイテレータがfor文で使えるか確認
for number in counter:
print(number)
# 出力:
# 0
# 1
# 2
# 3
# 4__iter__と__next__というルールを守ってクラスを作るだけで、for文で使える便利なオブジェクトが自作できました。
StopIterationでループの終わりを教える
__next__メソッドの中でraise StopIterationを呼び出すのは、非常に重要です。
これがないと、for文はいつループを終えればいいのか分からず、プログラムが止まらない無限ループになってしまいます。StopIterationは、イテレータがfor文に「お仕事はここまでです!」と伝えるための大切な合図なのです。
なぜイテレータを使うの?そのメリットとは
イテレータのメリットは、なんといってもメモリに優しいことです。
メリット:メモリ効率が非常に良い
例えば、1から1億までの数字が必要な場合を考えてみてください。
もしこれをリストで作ると、1億個の数値をすべてコンピュータのメモリに保存する必要があり、膨大なメモリを消費してしまいます。
# 1億個の要素を持つリスト。非常に多くのメモリを使う
# numbers = list(range(100000000))しかしイテレータなら、next()が呼ばれた瞬間に次の値を計算して返すだけです。すべての値を事前にメモリに保存しておく必要がありません。
この特性のおかげで、非常に大きなデータ(例えば、巨大なファイルの1行ごとなど)を扱う場合でも、メモリ不足を心配することなく、効率的に処理を進めることができます。
まとめ
今回は、Python初心者の方に向けて「イテレータ」の基本を解説しました。
- イテレータとは、データを順番に一つずつ取り出すための道具。
- リストなどのIterableから
iter()関数でイテレータが作られる。 for文は、このイテレータのnext()を繰り返し呼び出すことで動いている。__iter__と__next__を実装すれば、イテレータは自作できる。- イテレータの最大のメリットは、メモリ効率が良いこと。
for文の裏側でこんな仕組みが動いていると知ると、なんだか面白いですよね。イテレータを理解することは、Pythonをより深く使いこなすための重要な一歩です。ぜひ、ご自身のコードでもこの仕組みを意識してみてください。


コメント