Pythonにおけるイテレーター

Pythonにおけるイテレーター

この記事ではPythonにおけるイテレーターについて説明します。

YouTube Video

Pythonにおけるイテレーター

概要

Pythonにおいて**イテレーター(iterator)**は、リスト、タプル、辞書などコレクションの要素を1つずつ順に処理するための基本的な仕組みです。

イテレーターとは?

イテレーターとは、要素を一つずつ取り出せるオブジェクトです。Pythonでは、以下の2つの条件を満たすオブジェクトがイテレーターと見なされます。

  • __iter__() メソッドを持ち、自身を返します。
  • __next__() メソッドを持ち、次の要素を返します。終端時には StopIteration を送出します。
1iterator = iter([1, 2, 3])
2print(next(iterator))  # 1
3print(next(iterator))  # 2
4print(next(iterator))  # 3
5# print(next(iterator))  # StopIteration occurs
  • このコードでは、iter() 関数でリストをイテレーターに変換し、next() 関数でその要素を1つずつ取り出して表示しています。

イテラブル(Iterable)との違い

イテラブルとは、__iter__() メソッドを実装しているオブジェクトで、for ループで反復処理できるものです。リストやタプルなどが該当します。

1nums = [10, 20, 30]
2it = iter(nums)  # Get an iterator from the iterable
3print(next(it))  # 10
  • このコードは、リストなどのイテラブルからイテレータを取得し、next() で要素を順に取り出す例です。

チェック方法:

1from collections.abc import Iterable, Iterator
2
3nums = [10, 20, 30]
4it = iter(nums)
5
6print(isinstance(nums, Iterable))  # True
7print(isinstance(nums, Iterator))  # False
8print(isinstance(it, Iterator))    # True
  • このコードは、nums がイテラブルである一方でイテレータではなく、iter(nums) によって得られる it がイテレータであることを確認しています。

for ループとイテレーターの関係

Pythonの for ループは、内部的に以下のように動作しています。

1nums = [1, 2, 3]
2iterator = iter(nums)
3while True:
4    try:
5        value = next(iterator)
6        print(value)
7    except StopIteration:
8        break
  • このように、for はイテレーターを暗黙的に利用して反復処理を行っています。

独自イテレーターの作成

クラスを使って、オリジナルのイテレーターを作ることができます。

 1class Countdown:
 2    def __init__(self, start):
 3        self.current = start
 4
 5    def __iter__(self):
 6        return self
 7
 8    def __next__(self):
 9        if self.current <= 0:
10            raise StopIteration
11        value = self.current
12        self.current -= 1
13        return value
14
15for num in Countdown(3):
16    print(num)  # 3, 2, 1
  • このコードは、Countdownクラスを使って、カウントダウンする独自のイテレータを定義し、forループで3から1まで出力する例です。

ジェネレーターとの違いと使い分け

イテレーターと似た機能を提供するのが**ジェネレーター(generator)**です。より簡潔にイテレーターを定義できます。

1def countdown(n):
2    while n > 0:
3        yield n
4        n -= 1
5
6for i in countdown(3):
7    print(i)  # 3, 2, 1
  • このコードは、yieldを使ってカウントダウンするジェネレーター関数を定義し、forループで3から1まで出力する例です。

イテレーター(クラス)とジェネレーター(関数)の違い

イテレーター(クラス)とジェネレーター(関数)には次のような違いがあります。

特徴 イテレーター (class) ジェネレーター (function)
定義方法 __iter__() + __next__() yield を使う関数
状態管理 手動で属性管理が必要 自動的に状態を保存
可読性 複雑になることもある シンプルで明快
  • 定義方法の違い イテレーターは、__iter__()__next__() という2つのメソッドを自分で書いて定義します。一方で、ジェネレーターは yield キーワードを使うだけの関数なので、コードがずっと簡単になります。

  • 状態管理の違い イテレーターでは、現在の状態や進行状況を自分で変数として管理しなければなりません。しかしジェネレーターは、Pythonが内部で状態を自動的に覚えてくれるので、手間がかかりません。

  • コードの見やすさ(可読性) イテレーターは、メソッドを複数用意したり状態管理が必要なので、どうしてもコードが複雑になりがちです。対してジェネレーターはシンプルな構文で書けるため、初めて見る人にも理解しやすいです。

イテレーターを活用する標準ライブラリ:itertools

Pythonの標準ライブラリであるitertoolsには、強力なイテレーター操作ツールが揃っています。

1import itertools
2
3for x in itertools.count(10, 2):  # 10, 12, 14, ...
4    if x > 20:
5        break
6    print(x)
  • 他にも cycle, repeat, chain, islice, tee など多くの関数が用意されています。

イテレーターを使ったユースケース

イテレーターを使ったユースケースには次のようなものがあります。

  • ファイルの行処理 : イテレーターとしてファイルから一行ずつ読めます。
  • メモリ効率のよい処理 : 巨大なデータを逐次処理できます。
  • 無限シーケンスの表現 : itertools.count() などを利用できます。

まとめ

  • イテレーターは、次の値を逐次取得できるオブジェクトです。
  • __iter__()__next__() を定義することで独自のイテレーターが作成可能です。
  • for ループや next() を通じて自動的に扱われます。
  • ジェネレーターや itertools を使えば、より効率的な処理が可能です。

イテレータを利用することで、メモリ効率の良い方法で大量のデータを順次処理し、プログラムのパフォーマンスを向上させながら制御可能な状態管理が行えます。

YouTubeチャンネルでは、Visual Studio Codeを用いて上記の記事を見ながら確認できます。 ぜひYouTubeチャンネルもご覧ください。

YouTube Video