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
コメント