Pythonのイテラブル(iterable)とイテレータ(iterator)のイメージ画像

Pythonのイテラブル(iterable)とイテレータ(iterator)

  • 公開日:2018/11/09
  • 更新日:2018/11/09
  • 投稿者:n bit

Pythonには、イテラブル(iterable)とイテレータ(iterator)と言う重要な概念があり、ある一定以上の段階を超えてコードを記述していくには必要な知識。今回は初心者向けにイテレータの理解に必要『iter関数、next関数』とあわせてわかりやすく解説します。

  • Python

この記事は約 分で読めます。(文字)

Pythonのイテラブル(iterable)とイテレータ(iterator)

Pythonにはイテラブル(iterable)とイテレータ(iterator)と言う概念があります。なかなか理解しにくい概念ですがしっかりと理解しておくことで今後配列を扱うコードを記述するときにどのオブジェクトや方法を選択すべきか迷いにくくなります。

また、最終的にはメモリの消費量などを抑えた効率的なコードの記述方法にもつながりますので頑張って学習しておきましょう。

イテラブル(iterable)とは

まずは『イテラブル(iterable)』について解説していきましょう。イテラブルと言う言葉はあまり聞きなれませんので言葉だけを聞いてもピンと来ないと思います。

イテラブルと言う言葉の意味は『反復可能な』や『繰り返し可能な』といった意味です。

Note

iterable

品詞 形容詞訳語:繰り返し可能な

出典:iterableの意味・使い方 - 英和辞典 Weblio辞書

『反復可能な』や『繰り返し可能な』と聞けばイメージしやすいオブジェクトがありますね。listやtuple、dictといった『for _ in』で回して取得できるオブジェクトです。

つまり、リストのようにオブジェクト内の要素を繰り返しアクセスして取得することができる構造を『イテラブル(iterable)』と呼び、そのような構造を持ったオブジェクトのことを『イテラブルなオブジェクト』と呼びます。

この『イテラブルなオブジェクト』から『for _ in』などを使って繰り返しアクセスして要素を取得することを『イテレーション』といいます。

少し荒っぽい理解にはなりますが『for _ in』でアクセスして要素を取り出す(イテレーションする)ことができる構造を『イテラブル』、オブジェクトを『イテラブルなオブジェクト』と理解しておいても良いでしょう。

# イテラブルなオブジェクト『list』

words = ['Python', 'CSS', 'HTML', 'JavaScript']

# イテレーション:繰り返しアクセスして要素を取得する
for text in words:
print(text)

# このような構造を『イテラブル』

出力結果

Python

CSS
HTML
JavaScript

イテレータ(iterator)とは

次は『イテレータ(iterator)』についてです。またよく似た名前が出てきましたね。

『イテレータ』は『イテラブルなオブジェクト』の中の1つでイテレーションした状態を記憶しておくことができるオブジェクト(イテレータ型のオブジェクト)です。

イテレータはPythonの組み込み関数『iter関数』を利用して生成することが可能で『イテラブルなオブジェクト』から『イテレータ』オブジェクトを生成することもできます。

実際にコードを見たほうが理解しやすいと思いますので下記のサンプルコードを確認してみてください。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


iter_words = iter(words)

print(type(words))
print(type(iter_words))

出力結果

<class 'list'>

<class 'list_iterator'>

iter関数で変換したイテレータ『iter_words』のタイプを確認すると『<class 'list_iterator'>』になっていることが確認できます。このようにイテラブルなオブジェクトをiter関数の引数として渡すことで『イテレータ』オブジェクトに変換することができます。

『イテレータ』は『イテラブルなオブジェクト』の1つですので『for _ in』でイテレータオブジェクト内の要素を全て取り出すことも可能ですが、Pythonの組み込み関数『next関数』を使っても要素を取り出すことができます。

イテレーションした状態を記憶する『イテレータ』

『イテラブルなオブジェクト』と『イテレータ』の違いは『イテレーションした状態を記憶しておく』ことができることでしたね。これを実際に『next関数』を使って確認してみましょう。

『next関数』の引数に『イテレータ』を渡すことでイテレータ内部の要素を1つずつ出力することができ、すべて出力するとイテレーションの最後を判定します。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


iter_words = iter(words)

print(next(iter_words))
print(next(iter_words))
print(next(iter_words))
print(next(iter_words))
print(next(iter_words))

出力結果

Python

CSS
HTML
JavaScript

# 9行目でエラーが出力される
Traceback (most recent call last):
File "Main.py", line 9, in <module>
print(next(iter_words))
StopIteration

出力結果にあるようにnext関数でイテレータ内部の要素を全て出力仕切ってしまうと最終『StopIteration』が表示されます。これはイテレータ内部の要素がすべて取り出され内部の要素がなくなっているということを表したものです。

イテレーションの途中でもそこまでの状態を記憶しているということをわかりやすくするためにnext関数でイテレータ『iter_words』内の要素を2つ出力した後『for _ in』でさらにイテレータを回してみましょう。

わかりやすいようにforループに入る前に一度print関数で区切りを入れておきました。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


iter_words = iter(words)

print(next(iter_words))
print(next(iter_words))

print('######## iterator roop start #######')
for text in iter_words:
print(text)

出力結果

Python

CSS
######## iterator roop start #######
HTML
JavaScript

出力結果を確認するとforループの中で出力されているのはイテレータ『iter_words』内の要素の後半2つ『HTML、JavaScript』だけが出力されているのを確認できます。

これはforループ前にnext関数でイテレーションした状態(2回next関数で出力した内容)を記憶しており、残り出力することができるのはforループに入った時点で残り2つになっていることを記憶していたということです。

今度はforループだけを使って確認してみましょう。先にリスト(words:イテラブルなオブジェクト)でテストします。リストである『words』はforループで2回ループさせた時いずれも要素が全て出力されます。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


print('######## iterable roop1 start #######')
for text in words:
print(text)

print('######## iterable roop2 start #######')
for text in words:
print(text)

出力結果

######## iterable roop1 start #######

Python
CSS
HTML
JavaScript
######## iterable roop2 start #######
Python
CSS
HTML
JavaScript

 しかしイテレータである「iter_words」をforループで2回ループさせると1回目のループで全てイテレーションされその状態を記憶しているため2回目のforループでは何も出力されません。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


iter_words = iter(words)

print('######## iterator roop1 start #######')
for text in iter_words:
print(text)

print('######## iterator roop2 start #######')
for text in iter_words:
print(text)

出力結果

######## iterator roop1 start #######

Python
CSS
HTML
JavaScript
######## iterator roop2 start #######

このようにlistやtuple、dictなどの『イテラブルなオブジェクト』とは違い、『イテレータ』オブジェクトは『イテレーションされた状態を記憶している』ため一度取り出した要素はもう次に取り出すことができないのです。

イテレータは何が便利なのか?

なんとなくイテレータの性質について理解できたでしょうか。では、このイテレータが使えることで何がどう便利になるのか次はその辺について確認していきましょう。

『イテレータ』が『イテラブルなオブジェクト』と違う点は『イテレーションした状態を記憶している』と言うことでしたね。先ほどからしつこいようにこの言葉を繰り返していますが、その理由はこれが『イテレータ』の特徴であり、またメリットでもあるからです。

次のサンプルコードを確認してください。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


iter_words = iter(words)

print(next(iter_words))
print('test1')
print(next(iter_words))
print('test2')
print(next(iter_words))
print('test3')
print(next(iter_words))
print('test4')

出力結果

Python

test1
CSS
test2
HTML
test3
JavaScript
test4

『next関数』でイテレータ内の要素を1つずつ出力する間に別の出力を行っています。これはイテレーションした状態を1回ずつ記憶しているからこそできることです。

イテレーションした状態を記憶することができない『イテラブルなオブジェクト(listやtuple、dictなど)』でこれと同じことを実現しようとすると結構大変。forループで一気に回ってしまいますので現在のイテレーションの状態を記憶するための変数等を別途用意する必要があります。

『イテレータ』であれば『イテレーションした状態を記憶』していると言う特徴と、すべての要素が出力され『StopIteration』が出るという特徴を利用することで便利なコードが色々と記述できますね。

今日のdot

今回学習したイテラブル(iterable)、イテレーション、イテレータ(iterator)がわかると次に学習するジェネレータもより理解しやすくなります。

言葉が似通っていて混乱しがちですが把握出来てしまうと内容自体はそんなに難しいことではありません。すぐに理解できなかった場合は何度か読み返しゆっくりと習得していきましょう。