Pythonでクラス変数を定義するには、クラス名の下に変数を宣言するよということになっている。公式ドキュメントでそのように書かれている。
sample.py
class Sample:
name = 'name'
s = Sample()
s2 = Sample()
print(s.name) # 'name'
print(s2.name) # 'name'
当たり前ですが、どちらも「name」と表示される。
でも、こんな感じでnameを変更した場合、クラス変数ではなくなってしまう。
sample.py
s = Sample()
s2 = Sample()
s.name = 'aaaa'
print(s.name) # 'aaaa'
print(s2.name) # 'name'
これを実行すると、s.name
はaaaaでs2.name
はnameと表示される。全てのオブジェクトでシェアされるのであれば、s2.nameもaaaa
に変わらなければならないはず。
答えとしては文字列はイミュータブルなので、オブジェクトを経由して参照すると自動的にインスタンス変数を作ってくれるということなんだろうか。
でも、Sample.name
にしてみたら、どちらもaaaaに変わった。クラス変数としての特性を持っている。参照元がクラスなのかオブジェクトなのかで、空気読んで解釈しているのかな?
配列や辞書型はミュータブルなので、下記を実行すると変更が伝搬され、どちらのprintも[1,2,3,4]
と表示される。同じものを指しているから当たり前。
sample.py
class Sample:
a_list = [1,2,3]
s = Sample()
s2 = Sample()
s.a_list.append(4)
print(s.a_list) # [1,2,3,4]
print(s2.a_list) # [1,2,3,4]
強引にまとめると
イミュータブルはクラスの下に宣言しても自動的にインスタンス変数に切り替わってくれて、ミュータブルはクラス変数のままである、という話でいいのかなこれ。原則、共有するよ。でも、イミュータブルなデータはオブジェクトを経由してアクセスするとインスタンス変数になるよ。
こんな仕様なのかなぁ。