リスト内包表記の評価タイミング
Pythonにはリスト内包表記というのがあり、リストなどの全ての要素に処理を施したい場合、1行で簡潔に書ける。
1 2 3 4 5 6 7 8 9 10 11 |
array = [0, 1, 2]array2 = [x + 1 for x in array] # <-これprint(array2)# => [1, 2, 3]# 処理的にはこれと一緒array3 = []for x in array: array3.append(x + 1)print(array3)# => [1, 2, 3] |
このarray、どのタイミングで評価されるかというと、通常のfor文と一緒で、ループのたびにarrayを参照して、逐次取り出される。
いや、当たり前っちゃ当たり前なのだが……
たとえばlist.extend()を使うとき。list.extend(iterable)は、iterableでlistを拡張する。
1 2 3 4 |
array1 = [0, 1, 2]array2 = [3, 4, 5]array1.extend(array2)# => [0, 1, 2, 3, 4, 5] |
iterableに「拡張元のlistのリスト内包表記」を用いる場合、listはループのたびに順次拡張される。結果、リスト内包表記がいつまでも終端に達せず、無限ループに陥る。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
array = [0, 1, 2]array.extend(x + 1 for x in array)# [0,1,2,1,2,3]になるのではなく、# arrayはループのたびに順次拡張され、無限ループに陥ってメモリを食いつぶして死ぬ# [0,1,2,1,2,3,2,3,4,3,4,5,...]for x in array: array.append(x + 1)# 要はこれと同じ。これも無限ループに陥る。array.extend([x + 1 for x in array])# => [0, 1, 2, 1, 2, 3]# 渡す前にリストにしてしまえば、もうarrayのiterationは完了しているので、大丈夫 |
listの拡張元に同じlistを使うことはあまり無いものの、忘れた頃についやってしまいがちなミス。しかもメモリが死ぬので何もできなくなってやばい。

