SAIG の佐藤尭彰です。最近は業務で Python ばっかり書いています。
今回は Python連載 の第4回目で、Python の中でも「なんとなく」で扱われがちなイテレータについてです。
イテレータとは
あるコンテナの中の要素に1つずつアクセスできるオブジェクト。
もう少し 公式 から引用すると、
(
iter()) 関数は、コンテナの中の要素に1つずつアクセスする__next__()メソッドが定義されているイテレータオブジェクトを返します。
つまり、コンテナの中身を1つずつ返す __next__() メソッドを持つ (ようなオブジェクトを返す __iter__() 関数を持つ) ことがイテレータの本質です。
list などのシーケンスと異なり、実態として中身が存在する必要がありません。これを実装するための1手段が ジェネレータ や ジェネレータ式 であり、返すべき値はこれらを呼び出すたびに都度計算してよいのです。このイテレータの性質から、イテレータを使えるところ (= iterable を要求されるところ) にシーケンスでなくイテレータを渡すとメモリや実行時間を削減できます。
一方でイテレータは実際に値が帰ってくるまでは中身が確定しません。確定させるためには list もしくは tuple などにキャストする必要があります。
print(map(lambda x: x**2, range(5)))  | 
▲ ざっくり printf デバッグをするときに忘れがちな list()
組み込みのイテレータ
組み込み = import なしに使える、標準のもの
よく見るもの
ここは使いこなしているユーザが多いのではないでしょうか。
map(func, iterable): 第2引数に第1引数を作用させたものを返すfilter(func, iterable): 第2引数に第1引数を作用させた結果が真値となる要素のみを返すenumerate(iterable): インデックスと中身のタプルを返すzip(iter1, iter2, ...): それぞれの iterable の i 番目からなるタプルを返す- 長さがまちまちなときは最短なもので止まる
 
あまり見ないけど便利なもの
本題その1です。
filter(None, iterable)- 第1引数に
Noneを渡すと、iterable内の要素自体が真値を返すような要素のみを返します - つまり「
None,False,0(と等価なもの),'',[], etc. 」を除くことができます。0が消えることを除いては かなり使い勝手がよく、無為なif文でインデントを1つ掘るよりも見通しの良いコードを書くことができます 
- 第1引数に
 
# やりがちな例  | 
reversed(seq)- いわゆるリバースイテレータを返します。逆順にしたコピーを返す 
[::-1]よりも軽くて便利なことが多いです - 一方で、(事実上)引数
seqはlistかtupleである必要があります 
- いわゆるリバースイテレータを返します。逆順にしたコピーを返す 
 iter(callable, sentinel): 2引数版iter- sentinel と一致するまで callable を叩いた返り値を返します
 - 文字通りの番兵がいるようなテキストデータ・バイナリデータをパースするときに役に立つ(かも)
 
itertools
本題その2です。
import することでいろいろなイテレータが作れます。どこで使うんだと言うのもありますが、大体はいつか使える関数です。
主な無限イテレータ
count(start[, step=1]): stop がない無限rangecycle(iterable):cycle('ABCD') --> A B C D A B C D A B C D ...- だいたい 
zipなどの 一番短いやつに揃えて止まる 系ジェネレータを止めたくないときに使います 
- だいたい 
 
主な(普通の)イテレータ
accumulate(p[, func])- 累積和。
np.cumsum(v) - このほか第2引数 func は幅広い二項演算を取ることができるため 
np.cumprodにしたり累積maxしたり色々できます 
- 累積和。
 chain.from_iterable(iterable)- 2重のネストに限定された 
np.ravelです- ネストされていない要素が混じっていたり、3重ネスト以上を平坦化したい場合はおとなしく 
collections.abc.Iterableかどうかを判定するしかないようです 
 - ネストされていない要素が混じっていたり、3重ネスト以上を平坦化したい場合はおとなしく 
 
- 2重のネストに限定された 
 
from itertools import chain  | 
▲ こんな感じで組むと flatten できる
groupby(iterable[, key])- 前から見ていって 
keyが一致するような要素集合を (key,要素集合) の形で返します - iterable がソート済ならばだいたい 
df.groupbyですが、ソートされていないとkeyが変わるたびにブロックを返すので敢えてそれを利用する使い道もあります- タイムスタンプ順にそろえておいて、同じ人の連続ログをひとまとめにして見たい、など
 - C++ の 
uniqと同じような動作です 
 
- 前から見ていって 
 islice(iterable[, start], stop[, step])iterable[start:stop:step]reversed同様、コピーを作らないのでメモリに優しいです
takewhile(pred, seq)predが偽になったら終了するイテレータ- リスト内包でbreakしたくなったらこれを思い出して下さい
 
おわりに
標準ライブラリを上手に使って快適な Python ライフを。
次回は10月7日、小橋昌明さんの pandasの内部で何が起きているか です。