Pythonのイテレータで無限ループしてしまった話と解決策3つ

Pythonイテレータって遅延評価で、それは普通いいことなんですけど、うっかり無限ループしてしまいました。

問題

リスト l の各要素に100を足して l にappendするつもりで以下のコードを書きました。

l.extend(map(lambda i: i+100, l))

map()イテレータを作り、 extend() により評価されるたびに第2引数の l (か iter(l) )の次の要素がyieldされるわけですが、 lextend() により長さが増えていくので、いつまでも終わりにたどり着かないわけですね。

解決策

リストをコピーする

extend() により伸びていくリストではなく、それを呼ぶ前のスナップショットをイテレートします。

l.extend(map(lambda i: i+100, l[:]))

イテレータを先に評価する

extend() より先に map() の評価を終わらせます。リスト内包でもいいです。

l.extend(list(map(lambda i: i+100, l)))

イテレータに終わりを設ける

extend() する前の長さで終わりにします。

from itertools import islice

l.extend(map(lambda i: i+100, islice(l, len(l))))