Python: オブジェクトのコピー
疑問
Intとlistではコピーしたときの挙動が違うように見える。
というのも、リストをコピーしたと思ったら元の変数が指すリストも変わってることがあることを経験したことがあるだろう。
これはなぜか?
答え
前提1: pythonの変数はポインターであって、変数自体がオブジェクトを持っているわけではない。
前提2: pythonでは、同じ数字を表すintオブジェクトは一つしか存在しない。一方で、listオブジェクトの場合、同じ要素で構成されるリストはいくつでも存在可能。
intの場合
同じ数字を表すintオブジェクトは一つしか存在しない。もし違う二つの変数(例えば変数aとb)の両方に同じ数値をassignした場合、両方とも同じオブジェクトをポイントしている。ここで、片方の変数(ここでは変数aとする)を違う値をassignしたり、incrementしたとする。このときpythonは:
1) 新しい数値のオブジェクトを作る。
2) 変数aは1)で作ったオブジェクトをポイントする。
つまり変数bのポインターは変わっていないし、ポイントしている先のオブジェクトにも変化はないということ。変わったのは変数aだけ。
listの場合
同じリスト(=同じ要素から成り立つリストオブジェクト)は何個でも存在することができる。intオブジェクトの場合と同じように二つの変数があり、両方とも、同じlistオブジェクトをポイントしていたとする。このとき、片方の変数の要素の一部(または全て)を変えたとする。このとき変数aもbも同じオブジェクトを指しているのだから、print(b)をすると、aと同じオブジェクトが出力される。
結論
結局なんでこのような現象が起きるのか?
どちらかというと特殊なのはintだといえる。「a += 3」としたとき、変数aがポイントするオブジェクトの値を変えるのではなく、新しいオブジェクトを作って(もしもともとaが5だとすれば、8というintオブジェクトをつくる)、それをポイントする。一方でリストは、要素を変えるときに、わざわざ新しいオブジェクトを作るのではなく、単純に、ポイントしているオブジェクトの要素を変える。