Pythonでのクラス属性とインスタンス属性
本稿ではクラス属性とインスタンス属性の違いについてのべ、クラス属性がどのような場合に有効かを紹介する。
class A(object):
val = 5 #すべてのインスタンスに共有されるクラス変数
def __init__(self):
class B(object):
def __init__(self, val=5):
self.val= val # 各インスタンスにユニークなインスタンス変数
上のようなコードでclass A,Bでどう違うのか?
まず違いとしてselfを使わずにインスタンス変数(メンバ変数)が定義できるという違いに気づく。
Pythonのクラスとクラスのインスタンスはそれぞれ、別々の区別されたnamespaceをもつ。ただし、注意すべき点は、インスタンスのnamespaceのほうがclassのnamespaceよりも優先されるということだ。すなわち両方に同じ名前の属性(attribute)が存在した場合, はじめにインスタンスのnamespaceから適合するものをチェックし存在したらインスタンスのものを返却する。存在しなければクラスのものを探しに行くという手順を踏む。
class変数の性質
class変数の性質について述べよう。class変数は値を途中で代入することができる。ただしこの場合、単にインスタンスごとに値が変更される
class A(object):
val = 5
def __init__(self):
a=A()
print a.val
>5
a.val=0
print a.val
> 0
a2=A()
print a2.val
>5
上のような挙動は以下のclass 属性の挙動をみれば納得できる
class C(object):
class_val = 5
def __init__(self,input):
self.var=input
c=C(1)
c.__dict__
>{'var': 2}
#class変数は値を途中で代入
c.class_val=0
>{'class_val': 0, 'var': 2}
上の結果から明らかなように、クラス変数を変更したとき、namespaceレベルでは、c.__dict__に(すなわちクラスのインスタンスのnamespaceに)class_val attributeを追加している!!さらに、すでに述べたクラスのnamespaceに対する、インスタンスのnamespaceの優位性から、インスタンスのnamespaceの結果が返却される.
一方他のインスタンス(class_valの値を変更してないインスタンス)では、上のような追加は行われないので、素直にクラスのattribuiteが参照される。
いつクラス属性を使うべきか??
上のようにクラス属性の挙動は少し複雑なものになっているが、果たして有用な場面はあるのだろうか??
以下の場合では有用かもしれない。
1.速度
class namespaceはクラスの定義が行われた時に一度きり作られるのでその分少しだけ早いです。
しかしこの程度のperformanceの違いが気になるならそもそもpythonを使うべきではないのかもしれません
2.クラスでしか使わない定数
c++ のstatic member.
3.各クラスのインスタンスごとに設定すると便利かもしれないt(典型的な)デフォルト値
例えばリストをメンバ変数としてもつとして、そのリストの上限を決める値。
4.インスタンス間で共通のデータ
一つのクラスに対して、インスタンスをいくつも作った時、各インスタンスで生成された情報の共通のデータを持っておきたい場合など。例として以下のようなもの。
class Person(object):
AllInstance = []
def __init__(self, name):
self.name = name
Person.AllInstance.append(self)
p1=Person("Kim")
p2=Person("Chan")
Person.AllInstance
> [<__main__.Person at 0x7f6409586810>, <__main__.Person at 0x7f64095865d0>]