Python、はじめました

非IT系私文卒リーマン vs Python の全記録

Pythonにおけるイテレータ

Pythonの教科書を見ていると、forやinの項目でよくイテレータ(iterator)という言葉が出てくる。どうやら繰り返しを意味する言葉らしい。けど、どういうものなのか説明されることもなくさらっと流される。

どうやらこれはPython特有のものではなく、C++JavaScriptにもあるプログラム用語だからのようだ。改めてPythonの教科書で説明することもないじゃん、ってこと。けど、初めて触ったプログラム言語がPythonの人にとっては未知の概念。

ここではその意味について自分なりにまとめたのを書いていきます。

 

はじめに(繰り返し処理の関係図)

f:id:pokita:20180513212945p:plain


上はそれぞれのオブジェクト型の関係図。ここの語句の説明は後述。

 

iteration(繰り返し処理)可能(iterable)なobjectは大きく分けて上図の3つ。sequence、container、iterator。そもそもiterationとは、iteratorを生成できるオブジェクトのことを指す。iteratoriterator自身なので、iterable。

sequenceやcontainer等のbuint_in_objectは、in演算子やfor文などの制御構文を使って繰り返し処理を行えるためiterableと言える。

ここで重要なのは iterator=iterable ではないということ。iteratorとはあくまでもiterableに属するより狭い概念であり、=ではない。iterator∈iterable

a = "spam"
for i in a:
print(i)
>>>s
p
a
m
#for構文に対応しているのでstr型はiterable

a = 123
for i in a:
print(i)
>>>TypeError: 'int' object is not iterable
#for構文に対応していないのでint型はiterableでない

d ={"a":111,"b":222,"c":333}
for i in iter(d.keys()):
#iter(d.keys())で生成されるdict_key.iteratoriterator
   print(i)
>>>a
b
c
#for構文に対応しているのでd.keys()はiterable
 

イテレーション(iteration)とは
イテレーション(iteration)・・・繰り返すこと。反復。

配列の各要素など、同種の複数の対象に同じ処理を順番に繰り返し実行する処理や、そのような処理を記述したコードのことを指す。

for文などの制御構文を用いてループ構造の処理を行う場合と、イテレータなど反復処理を行うために用意された関数(next)などを呼び出して処理を依頼する場合がある。

 

イテラブル(iterable)とは
イテラブル(iterable)・・・iteration可能な構造のこと。

イテレーションの処理に対応しているオブジェクトの特性のことをイテラブルと呼ぶ。

 

イテレータiterator)とは
 イテレータ(iterator)・・・iterationした場所を記憶しているという特性を持つオブジェクトのこと。

iter関数やkeysメソッド※やzip関数等で生成される。リストや文字列とは異なる、関数により生成されるオブジェクトとして消化すると理解しやすい。(keysメソッドで生成されるdict_keysオブジェクトはsetオブジェクトのような機能を有するviewオブジェクトであり、iteratorではない。)

ここを理解するのに結構時間がかかった。詳しい経緯は下。

 

iteratorの特徴は、内包するobjectをnext関数を使って吐き出すことである。iter関数を使って作ることができる。見ていこう。

a = iter("spam")
#iterableなobjectならiter関数の引数になり得る。
print(a)
>>>str_iterator object at 0x05525210
#x_iterator objectは__repr__()を持たないため、出力されるとObject名at iddressで表示される。
print(list(a))
>>>["s","p","a","m"]
print(next(a))
>>>"s"
print(next(a))
>>>"p"
print(list(a))
>>>["a","m"]
#next関数で"s"と"p"が吐き出されたため、内包されているのは"a"と"m"
 図にすると以下のようになる。

 

 

iteratorはlistやtupple同様のcontainerであり、objectへのリファレンスを保持しているだけに過ぎない。そのため、next関数を使ってその内包objectが変わろうとも、その同一性(id)は保たれる。

 

ここでiter関数について一つ。iter関数で作られたiteratorはあくまでもiter関数の引数のリファレンスを持つobjectであり、引数に変更が加えられた際は、その影響を受ける。

L = [1,23]
i = iter(L)
L.pop()
print(next(i))
>>>1
print(next(i))
>>>Stopiteration
#Lの内容に変更がLを引数に持つiにも影響を及ぼしている。
 

最後に、iterableなobjectの再掲。

 

 

今回は以上。