リストとタプルみたいに見た目はよく似ているけど、実はぜんぜん違う。
リスト内包表記
>>> power_list = [n**2 for n in range(5)] >>> power_list [0, 1, 4, 9, 16] >>> for n in power_list: ... print n ... 0 1 4 9 16
ジェネレータ式
>>> power_gen = (n**2 for n in range(5)) >>> power_gen <generator object <genexpr> at 0x103547cd0> >>> for n in power_gen: ... print n ... 0 1 4 9 16
イテレータとして使う限りは全く同じ挙動に見えるけど、
リスト内包表記は、作成時にリストの中身を全て計算して、リストを作成しているのに対して、
ジェネレータ式は、呼び出された際に順に式を計算している。
リストを丸ごと記憶しておく必要がないので、メモリの使用を抑えられる。
そもそもジェネレータとは、こんな感じ。
>>> def power_func(): ... n = 0 ... while True: ... yield n**2 ... n += 1 ... >>> fun = power_func() >>> fun.next() 0 >>> fun.next() 1 >>> fun.next() 4 >>> fun.next() 9 >>> fun.next() 16
このyield文を上手く説明できないんだけど、僕の認識だと、
値を返して、ここまで計算したよというのを覚えておく式、という感じ。
next()が呼び出されると、yield文の続きから計算を行う。
だから、関数power_func()のように終わりのないループを書くと、
>>> for n in power_func(): ... print n ... 0 1 4 9 16 25 36 49 ...のように、延々とイテレーションが回ってしまう。
けど、逆に言えば、何か処理を行った際の値でループを抜けるように書けば良い話。
うーむ、pythonicな書き方に慣れないとな。
0 件のコメント:
コメントを投稿