リスト内包表記の評価タイミング
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を使うことはあまり無いものの、忘れた頃についやってしまいがちなミス。しかもメモリが死ぬので何もできなくなってやばい。