Python のリストでは=の使用注意

確認したバージョンはPython 3.6.1

それは.extend()を使ったとき起こった。
#基本
```py3
#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を追加しようとした。

#問題のコード
```py3
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']
```
あれ〜？

方法を変えてみよう


```py3
a = ["dog", "cat", "rabbit"]
b = list("333")#['3', '3', '3']
c = [2, "toka", 3.4, "みたいな混在もOK"]
d = [a,b]
```
ここまではいじらずに、処理を変えてみる

```py3
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　という処理。
うまくいくわけ無いか。
なら


```py3
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を共通化という処理がなされたよう。

```py3
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への処理と同じ意味を持ったと。
何じゃそりゃ。

#解決策
未だ初心者のため詳しい仕組みはわからない。
とりあえず成功例から考えて、何かの処理を加えて単なるコピーじゃなくしたらいけるかと、スライスを使ってコピーすることに

```py3
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
"""
```

とりあえず成功。
~~これが何らかのバグなのか、それとも仕様なのかは不明。~~
こういう仕様のようです。

他の方法としては、

```py3
e = d
e = e[:]
```
```py3
e = list(d)
```

でもdとeのIDは別になった。

#因みに

これは果たして、リストだけに起こる問題なのか？
と思い下のコードを実行

```py3
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は引き継がれる模様。