Pythonのクラスにまつわる話題を色々と学んできましたが、ここではクラス変数とクラスメソッド、スタティックメソッド(静的メソッド)について扱います。
クラス変数は、クラス定義の中に通常の変数と同じように定義された変数です。
クラスメソッド、スタティックメソッド(静的メソッド)は通常のメソッドとは違う性質があるのでここで見ていきたいと思います。
クラス変数
ではクラス変数について扱っていきましょう。簡単なコードでやっていきます。
次のようなクラスを作って、オブジェクトを呼び出してみます。
class Bird():
def __init__(self, name):
self.kind = "鳥類"
self.name = name
def whats_bird(self):
print(self.name, self.kind)
duck = Bird("アヒル")
duck.whats_bird()
crow = Bird("カラス")
crow.whats_bird()
Birdクラスの中に初期化メソッドを定義して、種類を示すkindという変数に「鳥類」という値を持たせます。もう一つ、引数としてnameを定義します。
そしてwhats_birdというメソッドを作って名前と種類を表示させるコードにしています。
「アヒル」と「カラス」を入れてインスタンス化してそれぞれ呼び出してみます。
実行するとこうなります。(class_etc.pyのファイル名でAtomで実行しています)
それぞれ与えた名前と、種類が呼び出されています。これは特に問題無い話だと思います。
ここでは、self.kind = “鳥類” がどちらにも共通しています。
これをクラス変数としてコードを書き換えるとこうなります。
class Bird():
kind = "鳥類" # クラス変数
def __init__(self, name):
self.name = name
def whats_bird(self):
print(self.name, self.kind)
duck = Bird("アヒル")
duck.whats_bird()
crow = Bird("カラス")
crow.whats_bird()
共通した部分をメソッド定義の中から取り出して、クラスのブロック定義の部分に持って行き、selfをつけずに変数として定義します。これがクラス変数です。
これを実行してみます。
結果は先ほどと同じになります。
duckもcrowも別々のオブジェクトですが、クラス変数の値の「鳥類」はどちらにも使われています。
このように、クラス変数は全てのオブジェクトの中で共有されるのが特徴です。
クラスメソッドとスタティックメソッド
今度はクラスメソッドとスタティックメソッドについて見ていきましょう。
上で使ったコードをもっと単純にして次のように変えてみました。
class Bird():
kind = "鳥類"
def __init__(self):
self.name = "カラス"
bird1 = Bird()
print(bird1)
bird2 = Bird
print(bird2)
クラス変数と、初期化したnameに値が与えられているだけです。
これをコードのようにクラスの丸括弧()をつけた場合と、つけない場合で呼び出してみるとこうなります。
丸括弧をつけた上側はオブジェクトになっていますが、下側はクラスのままです。
そこで、次のようにnameを呼び出してみます。
bird1 = Bird()
print(bird1.name)
bird2 = Bird
print(bird2.name)
するとこうなります。
オブジェクト化された上側は結果が表示されていますが、下側は初期化メソッドが実行されていないので、nameの属性が読み込まれません。
次はこのクラスのクラス変数にアクセスしてみます。
bird1 = Bird()
print(bird1.kind)
bird2 = Bird
print(bird2.kind)
コードそのままでどちらもkindを呼び出してみるとこうなります。
このようにクラス変数は、オブジェクト化しなくても呼び出すことができました。
今度は同様にクラス変数を呼ぶのですが、クラス変数を呼び出すメソッドを定義したコードを作ってみます。
class Bird():
kind = "鳥類"
def __init__(self):
self.name = "カラス"
def whats_bird(self):
print(self.kind)
bird1 = Bird()
bird1.whats_bird()
bird2 = Bird
bird2.whats_bird()
こちらも丸括弧をつけた場合と、つけ無い場合とでメソッド内のクラス変数を表示させてみるとこうなります。
先ほどは呼ぶことができていたクラス変数も、メソッドで呼び出す形にしてしまうと、オブジェクト化して無ければ呼ぶことができません。
@classmethodとcls
こういう時に、これを表示させるにはクラスメソッドを利用します。それには@classmethodとclsを使います。clsはclassの意味です。
上のコードを次のように書き換えます。
class Bird():
kind = "鳥類"
def __init__(self):
self.name = "カラス"
@classmethod # デコレータを入れる
def whats_bird(cls): #selfの代わりに cls
print(cls.kind) #selfの代わりにcls
bird1 = Bird()
bird1.whats_bird()
bird2 = Bird
bird2.whats_bird()
メソッドに@classmethodというデコレータを入れて、自分を示すselfの代わりにクラスを示すclsをを使います。
これを実行してみましょう。
先ほどオブジェクト化されずに表示できなかったクラス変数も、こちらでは表示することができています。
次のようにしても、どちらもアクセスすることができます。
Bird.whats_bird()
print(Bird.kind)
このように、クラスメソッドを使えば、オブジェクトを作らなくてもメソッドにアクセスすることができるのです。
@staticmethod
次は静的メソッド(スタティックメソッド)を見ていきましょう。デコレータの@staticmethodを使っていきます。
上のコードに一つメソッドを次のように加えます。
class Bird():
kind = "鳥類"
def __init__(self):
self.name = "カラス"
@classmethod
def whats_bird(cls):
print(cls.kind)
@staticmethod # デコレータを付けます
def watch(times): #引数は特に必要なく、selfは使いません。
print("今日は{}回、飛んでるのを見ました!".format(times))
Bird.watch(10)
watch()というメソッドを用意しました。スタティックメソッドを作るには、デコレータの@staticmethodを付けます。クラスに定義するメソッドには引数にかならすselfを入れますが、静的メソッドを作る時には必要ありません。clsも必要ありません。
ここでは回数を使う為にtimesを引数に用意してみました。
10を引数に入れて呼び出しています。
実行してみます。
呼び出しが実行されて表示されているのがわかります。
このスタティックメソッドは、クラスの中の他のデータにアクセスしないので、デコレータの@staticmethodを外して、クラスの外に関数定義を置いてそのまま利用しても同じ動きを得ることはできます。
ただ、他のコードとの違いとこのクラスとの関連性を考えてスタティックメソッドとして利用していますが、あまりスタティックメソッドとしてコードを書く機会は少ないとも言われています。
こういう書き方があるということだけ頭に入れておきましょう。
まとめ
Pythonのクラス変数は、クラス定義の中でのグローバル変数のような動きをします。クラス変数は全てのオブジェクトの中で共有されるのが特徴です。selfを付けずに定義します。
クラスメソッドはデコレータとして@classmethodと、selfの代わりにclsを使って定義します。クラスメソッドを利用すると、オブジェクトを作らなくてもアクセスすることができます。
スタティックメソッドは、デコレータに@staticmethodを付けて定義します。引数にselfは必要ありません。そのまま実行できます。