Pythonのイテレータについてまとめてみた

スポンサーリンク
Python基礎
スポンサーリンク

Pythonでのイテレータについてまとめてみました。なかなか初心者には難しいイテレータですが、複雑なアルゴリズムを組むのには上手なイテレータの活用は欠かせません。いろいろなイテレータの使い方を解説します。

イテレータとは

イテレータ」(出典: フリー百科事典『ウィキペディア(Wikipedia)』)によると、「プログラミング言語において配列やそれに類似する集合的データ構造(コレクションあるいはコンテナ)の各要素に対する繰り返し処理」の「抽象化」(イメージ)のことを言うそうです。よく分かりませんね。。。いわゆるプログラムの基本3要素、『順次・分岐・反復』のうち、反復にあたる処理にあたるようです。実は、よく使うFor文の中で、イテレータが使われているそうです。

greetings = ['good morning', 'hello', 'good bye', 'good night']

for greeting in greetings:
    print(greeting)

上のプログラムでは、リストをFor文で回してやると、リストから、値を一つずつ取り出してくれます。これができるのは、For文の中でイテレータを利用してくれているからです。イテレータを生成できる型のデータはイテラブルなオブジェクトと呼ばれていて、そのようなオブジェクトはリスト型以外に、文字列型、タプル型、辞書型、セット型などがあります。

このようにFor文のようにライブラリの内部ではイテレータの仕組みがよくつかわれています。イテレータはループで回すデータのうち、必要なところしか読み込まないので、特に大きなデータを扱う場合に非常に有効になります。

組み込み関数でイテレータ生成

Pythonではイテレータを組み込み関数のIter()を使うことによって、作って使うことができます。その場合、イテレータの中の値はnext()によって、一つずつ呼び出されます。下の例では、リストからイテレータを作っています。作ったイテレータはnextで呼び出すこともできますし、for文の中で使うこともできます。注意点は、一度呼び出した値は消えてしまい、再利用できないことと、空になった後、さらに呼び出そうとすると「StopIteration」のエラーでプログラムが停止してしまうことです。For文の中で使った場合も、再利用はできません。

greetings = ['good morning', 'hello', 'good evening', 'good bye', 'good night']

g=iter(greetings)
print(type(g))

print(next(g))
print(next(g))

print('################')

# For文で2つだけ出力
n = 0
for greeting in g:
    print(greeting)
    n += 1
    if n == 2:
        break
    
print('****************')
print(next(g))

print('----------------')
print(next(g))
<class 'list_iterator'>
good morning
hello
################
good evening
good bye
****************
good night
----------------
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
Input In [39], in <cell line: 22>()
     19 print(next(g))
     21 print('----------------')
---> 22 print(next(g))

StopIteration:

クラスでイテレータ生成

イテレータは下記のようにクラスで記述することもできます。その場合、クラスでは__iter__()メソッドと__next__()メソッドでイテレータを記述します。ただ、同じことは後述するジェネレータ関数を使うともっと簡単にできます。

# イテレータの定義
class Print_even:
    def __init__(self, max):
        self.max = max

    def __iter__(self):
        self.num = 0
        return self

    def __next__(self):
        if(self.num >= self.max):
            raise StopIteration
        self.num += 2
        return self.num

# オブジェクト生成(10までの偶数)
print_even = Print_even(10)
i = iter(print_even)

print(next(i)) 
print(next(i)) 
print(next(i)) 
print(next(i))
print(next(i))

# StopIteration
# print(next(i))
2
4
6
8
10

ジェネレータ関数でイテレータ生成

ジェネレータ関数を使うことでイテレータを簡単に生成できます。任意の関数で値をreturnで返す代わりにyieldを使います。下の例は素数は出力するイテレータの例です。通常のイテレータと同じように値は再利用されず、next()やFor文の中で新しい値を出力し続けます。

# 素数ジェネレータ
def sosu():
    for i in range(2, 100):
        for j in range(2, i):
            if i % j == 0:
                break
        else:
            yield i

# オブジェクト生成
nums = sosu()
print(type(nums))

# printで出力
print(next(nums))
print(next(nums))

# For文で出力
n = 0
for num in nums:
    print(num)
    n += 1
    if n > 3:
        break

# printで出力
print(next(nums))
print(next(nums))
<class 'generator'>
2
3
5
7
11
13
17
19

ジェネレータ式でイテレータ生成

イテレータはジェネレータ式を使って非常に簡単に作ることもできます。リストの内包表記と同じような表記で、違う点は角括弧が丸括弧になったところくらいです。使い方は、他のイテレータと同じです。非常に簡単ですね。

# ジェネレータ生成
gen = (x*2 for x in range(10))
print(type(gen))

print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
<class 'generator'>
0
2
4
6

コメント