変数に関して

6月20日の自分の日記でPythonの変数の概念を勘違いしていた。私は、整数型の値を持つ変数は、値型として扱われると思っていたが、そうではなかった。つまり、型によって値型と参照型を内部で自動的に分けていると思っていたが、それは間違いだった。


以下の2つがポイントである。

  • 変数が他の変数にリンクされることはない
  • 変数はすべて、オブジェクトへの「ポインタ」である


つまり、すべての変数は参照型であり、値型の変数というものは存在しない。では、以下の挙動を考えてみよう。

a = 3
b = a
c = a
a = a + 1
print b, c #=> 3 3

A = []
B = A
C = A
A.append(1)
print B, C #=> [1] [1]

まず、bとcは、aが指している「3」というオブジェクトを参照している。a = a + 1とした時点で、新たな「4」というオブジェクトが作成され、これをaが参照する。しかし、bとcが指しているものは、「3」というオブジェクトであり、aではない。


次に、BとCは、Aが指している「[]」というリストのオブジェクトを参照している。A.append(1)とすると、AとBとCが指しているオブジェクト自身が変化し、BとCの内容も当然変わる。


ここで重要なのが、bやcが指しているオブジェクトは、イミュータブルであり、BやCが指しているオブジェクトは、ミュータブルであるということだ。つまり、a自身を変化させようと思っても不可能で、新たなオブジェクトを作成するしかなくて、それを指しているbやcは、まるで値のように振舞うということだ。
つまり、値型と参照型で何が違うと言えば、オブジェクト自身を変更したときの挙動だ。しかし、イミュータブルなオブジェクトであれば、(メモリ管理を除けば)違いがない。


また、自分の5月28日の日記のポインタ型と値型の表記がC++で違うことに関しては、Pimplイディオムなどで、どちらの場合も値型として扱えるようにすれば問題ないと思われる。


5月26日の問題もやっと理解できた。結局、Pythonでは全てがオブジェクトで、変数の値は、ポインタ値しか持てないと考えておけば良い。
あと分かったことは、「型」には、以下の2種類あるということだ。



2種類の型

  • IntegerやStringなどのようなオブジェクトの種類を表す型
  • メモリ領域を直接指す(値型)、メモリ領域を間接的に指す(参照型)などのメモリ領域の指し方の型


今さらながらやっと分かったという感じである。