確認したバージョンはPython 3.6.1
それは.extend()を使ったとき起こった。
#基本
#3つリスト作って
a = ["dog", "cat", "rabbit"]
b = list("333")#['3', '3', '3']
c = [2, "toka", 3.4, "みたいな混在もOK"]
d = [a,b]
print(d)
ここまでなら、間違いなく[['dog', 'cat', 'rabbit'], ['3', '3', '3']]が表示される。
そしてリストを追加する関数として.extend()があり、これでcを追加しようとした。
#問題のコード
a = ["dog", "cat", "rabbit"]
b = list("333")#['3', '3', '3']
c = [2, "toka", 3.4, "みたいな混在もOK"]
d = [a,b]
#dと比較するためにeにdを代入して
e = d
#.exrend()でeにcを挿入
e.extend(c)
#では比較を
print("d=", d)
print("e=", e)
結果表示されたのは
d= [['dog', 'cat', 'rabbit'], ['3', '3', '3'], 2, 'toka', 3.4, 'みたいな混在もOK']
e= [['dog', 'cat', 'rabbit'], ['3', '3', '3'], 2, 'toka', 3.4, 'みたいな混在もOK']
あれ〜?
方法を変えてみよう
a = ["dog", "cat", "rabbit"]
b = list("333")#['3', '3', '3']
c = [2, "toka", 3.4, "みたいな混在もOK"]
d = [a,b]
ここまではいじらずに、処理を変えてみる
e = d
#.extend()と同じ結果が+=でもできる。
e += c
print("d=", d, "\n", "e=", e)
"""結果
d= [['dog', 'cat', 'rabbit'], ['3', '3', '3'], 2, 'toka', 3.4, 'みたいな混在もOK']
e= [['dog', 'cat', 'rabbit'], ['3', '3', '3'], 2, 'toka', 3.4, 'みたいな混在もOK']
"""
失敗。
そもそも、いじってないはずのdが変化してるのだ。
しかも、加えるのをeではなくdに変えても結果は同じ。
原因はほぼ確実に e = d という処理。
うまくいくわけ無いか。
なら
e = d + c
print("d=", d, "\n", "e=", e)
"""結果
d= [['dog', 'cat', 'rabbit'], ['3', '3', '3']]
e= [['dog', 'cat', 'rabbit'], ['3', '3', '3'], 2, 'toka', 3.4, 'みたいな混在もOK']
"""
成功。
やはり、e = d が問題のようだ。
しかし、なんでこんなことに?
#原因
どうも、e = dで行われたのはeにdのリストをコピーではなく、eとdという変数のIDを共通化という処理がなされたよう。
a = ["dog", "cat", "rabbit"]
b = list("333")#['3', '3', '3']
c = [2, "toka", 3.4, "みたいな混在もOK"]
d = [a,b]
e = d
#id()で変数のidを確認。
print("d=", id(d), "\ne=", id(e))
e.extend(c)
print("d=", d)
print("e=", e)
print("d=", id(d), "\ne=", id(e))
"""
結果
d= 4738395144
e= 4738395144
d= [['dog', 'cat', 'rabbit'], ['3', '3', '3'], 2, 'toka', 3.4, 'みたいな混在もOK']
e= [['dog', 'cat', 'rabbit'], ['3', '3', '3'], 2, 'toka', 3.4, 'みたいな混在もOK']
d= 4738395144
e= 4738395144
"""
つまり、eとタグ付けされた箱にdとタグ付けされた箱と同じ物を入れたのではなく、eというタグをdとタグ付けされた箱に貼っただけと。
だから、eへの処理はdへの処理と同じ意味を持ったと。
何じゃそりゃ。
#解決策
未だ初心者のため詳しい仕組みはわからない。
とりあえず成功例から考えて、何かの処理を加えて単なるコピーじゃなくしたらいけるかと、スライスを使ってコピーすることに
a = ["dog", "cat", "rabbit"]
b = list("333")#['3', '3', '3']
c = [2, "toka", 3.4, "みたいな混在もOK"]
d = [a,b]
#e = dをe = d[:]に変更
e = d[:]
e.extend(c)
print("d=", d, "\n", "e=", e)
print("d=", id(d), "\n", "e=", id(e))
"""結果
d= [['dog', 'cat', 'rabbit'], ['3', '3', '3']]
e= [['dog', 'cat', 'rabbit'], ['3', '3', '3'], 2, 'toka', 3.4, 'みたいな混在もOK']
d= 4738473480
e= 4739188744
"""
とりあえず成功。
これが何らかのバグなのか、それとも仕様なのかは不明。
こういう仕様のようです。
他の方法としては、
e = d
e = e[:]
e = list(d)
でもdとeのIDは別になった。
#因みに
これは果たして、リストだけに起こる問題なのか?
と思い下のコードを実行
a = 1
b = 2
c = b
print("ID(a)=", id(a), "\nID(b)=", id(b), "\nID(c)=", id(c))
b += a
print(a,b,c)
print("ID(a)=", id(a), "\nID(b)=", id(b), "\nID(c)=", id(c))
"""結果
ID(a)= 4506339328
ID(b)= 4506339360
ID(c)= 4506339360
1 3 2
ID(a)= 4506339328
ID(b)= 4506339392
ID(c)= 4506339360
"""
こっちでは、c = bの時点ではIDはおなじだったが、b += aの処理でbのIDが変更された。
その後、a,bをリストにして試したら上の問題が発生。
少なくとも普通の計算では起こらない模様。
安心するべき・・・か?
むしろ、この単純計算だからこそこういった結果になっただけで、オブジェクト(変数)の中にオブジェクト(変数)が入る処理なら、同様の問題が起こるもよう。(set()とか、dict()でも確認)
#更に、因みに
問題のコードで
e = d のままにして
e.extend(c)の処理の代わりに、
- e.append()やってみた。
- 同じ問題が起きた。
- e[1]=[9]にした
- 同じ問題が起きた。
- e.remove(['3', '3', '3'])してみた
- 同じ問題が起きた。
- e = [0]にした。
- eのID変わった。
どうやら、元の形式をベースに変更する限りIDは引き継がれる模様。