問題のPythonスクリプト(Windows版Python3.5)
from sys import stderr
from copy import copy
N = 5
L1 = list(range(1,N + 1)) #[1,2,3,4,5]
print("L1 =", L1, file = stderr)
L2 = map(lambda i: i ** 2, L1)
L3 = map(lambda i: i ** 2, L1)
L4 = copy(L2)
L5 = [i ** 2 for i in L1]
L6 = list(map(lambda i: i ** 2, L1))
print("L2 =", list(L2)) #[1,4,9,16,25]
print("L2 =", list(L2)) #[1,4,9,16,25]・・・だと思うじゃん???
print("L3 =", list(L3)) #[1,4,9,16,25]
print("L4 =", list(L4)) #[1,4,9,16,25]・・・だと思うじゃん???
print("L5 =", list(L5)) #[1,4,9,16,25]
print("L5 =", list(L5)) #[1,4,9,16,25]
print("L6 =", list(L6)) #[1,4,9,16,25]
print("L6 =", list(L6)) #[1,4,9,16,25]
print("L1 =", L1)
実行結果
L1 = [1, 2, 3, 4, 5]
L2 = [1, 4, 9, 16, 25]
L2 = []
L3 = [1, 4, 9, 16, 25]
L4 = []
L5 = [1, 4, 9, 16, 25]
L5 = [1, 4, 9, 16, 25]
L6 = [1, 4, 9, 16, 25]
L6 = [1, 4, 9, 16, 25]
L1 = [1, 2, 3, 4, 5]
これからわかったこと
これから分かることは、mapで生成したオブジェクトへのアクセスは一度だけ有効である(L2
・L3
)ということです。しかも、copy.copy
で浅いコピー(L4
)をしても無駄でした。何回もアクセスするときはリスト内包表記を使う(L5
、ただし外側は角括弧)か、即座にリストorタプル化(L6
)すべきですね。mapオブジェクトの中身をデバッグで表示しなければならない時、このような特性によるデバッグ時のみの原因不明のバグにハマるかもしれません。
コメント欄での指摘がありましたが、丸括弧でジェネレーター内包表記を行うと、map同様使い捨てになります。
mapの使いどき
基本的に生成してからのアクセスを1度だけ(L6
のようにリストorタプル化することも含む)にすればL2
・L4
のような事態を回避できます。
他のオブジェクトについて
range
・zip
なども似たようなオブジェクトを生成しますが、これらも使い捨ての可能性があります。です。(コメントでの指摘より)複数回アクセスする場合はご注意ください。