Pythonの参考書や公式リファレンスを見ているとイテレータやイテラブルという単語がよく出てきます。この言葉に馴染みのない初学者の方などは難しく感じてしまうかもしれません。
そこで本記事では、そもそもイテレータやイテラブルとは何か、そして何が違うのか、について判りやすくまとめました。
確認した環境
- OS: Ubuntu 16.04LTS
- Python: ver3.7.0
イテレータ(Iterator)とは
イテレータは連続するデータを表すオブジェクトで、一度に一つの要素を順次返します。また、以下2つのイテレータプロトコルを実装しています。
__next__()メソッド | 次の要素を返す。要素が尽きたらStopIteration例外を送出 |
__iter__()メソッド | イテレータ自身を返す |
イテレータの作り方
イテレータは、iter()関数に任意のオブジェクト渡すことで作ることができます。
また、次の要素を返すにはnext()関数を使います。要素がなくなったらStopIterationエラーが送出されます。上記の__next__()メソッドと同じです。以下に例を示します。
#リストの例
>>> s = [1, 2, 3]
>>> i = iter(s)
>>> next(i)
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)
Traceback (most recent call last):
File "", line 1, in
StopIteration
リストをiter()関数に渡すことでリストのイテレータを生成し、next()関数で次の要素を返しています。最後に要素が無くなったらStopIteration例外を送出していることがわかります。
ここで、イテレータを作ることができるオブジェクトを、イテラブルなオブジェクトと呼びます。イテレータを作成できない場合はTypeErrorとなります。以下はint型データ(イテラブルなオブジェクトではない)をiter()関数に渡した例です。
#int型はイテラブルではない
>>> a = 10
#この場合、TypeErrorとなります
>>> iter(a)
Traceback (most recent call last):
File "", line 1, in
TypeError: 'int' object is not iterable
forループにおけるイテレータ
forループは、StopIteration例外が送出されると終了するように作られています。よってイテレータをforループ文で使うことができます。
「for A in B」のBは、イテレータまたはイテラブルなオブジェクトである必要があります。Bにイテラブルなオブジェクトが渡されると、イテレータが生成されループ処理が実行されます。このことは、以下の2つのコードが同じ意味であることを示しています。
>>> s = [1, 2, 3]
#リスト(イテラブル)をforループに渡す
>>> for i in s:
... print(i)
...
1
2
3
#イテレータをforループに渡す
>>> for i in iter(s):
... print(i)
...
1
2
3
イテレータのアンパック
シーケンスのアンパックもイテレータに対応しています。イテレータが返す要素の数Nがわかっていれば、以下のようにN-タプルにアンパックすることができます。
>>> s = [1, 2, 3]
>>> s_ = iter(s)
>>> s1, s2, s3 = s_
>>> s1, s2, s3
(1, 2, 3)
また、複数のシーケンスをアンパックして新しいシーケンスを作成する場合や、別の単独要素と一緒にアンパックして新しいシーケンスを作成する場合は、“*”を用いて以下の様に出来ます。
>>> x = ['a', 'b', 'c']
>>> y = ['d', 'e', 'f']
#複数のシーケンスをアンパックして新しいシーケンスを作成
>>> [*x, *y]
['a', 'b', 'c', 'd', 'e', 'f']
#別の単独要素を一緒に新しいシーケンスを作成
>>> *x, 'g', 'h'
('a', 'b', 'c', 'g', 'h')
#一つのシーケンスの場合はエラー
>>> *x
File "", line 1
SyntaxError: can't use starred expression here
イテラブル(Iterable)とは
イテラブルなオブジェクトは要素を1回に1つずつ返す機能をもったオブジェクトで、以下が該当します。
- 全てのシーケンス型(リスト、タプル、文字列)
- 非シーケンス型(辞書、ファイルオブジェクト)
- __iter__()を持つオブジェクト
- __getitem__()を持つオブジェクト
尚、リストはイテラブルなオブジェクトではありますがイテレータではありません。
実際の例で見てみます
>>> s = [1, 2, 3]
#リストをnext()関数に渡してもエラーとなる
>>> next(s)
Traceback (most recent call last):
File "", line 1, in
TypeError: 'list' object is not an iterator
<参考記事>それぞれのデータ型がどのような特徴があるのか(個人的に)ややこしいので、下記にてまとめてみました。ご参照ください!
まとめ
今回は、イテレータとイテラブルについて学びました。
- イテレータ:以下2つのイテレータプロトコルを実装したコンテナオブジェクト
- __next__()メソッド
- __iter__()メソッド
- イテラブル:iter()関数でイテレータを作ることのできるオブジェクト
- 全てのシーケンス型(リスト、タプル、文字列)
- 非シーケンス型(辞書、ファイルオブジェクト)
- __iter__()を持つオブジェクト
- __getitem__()を持つオブジェクト
コメント
[…] […]
[…] 標準組込み関数reversed() は、引数seqの要素を逆順に並び替えたイテレータ を返します。使い方は下記です。 […]