Pythonのオブジェクト指向プログラミングで使えるクラス変数とクラスメソッドについて学びましょう。クラス変数はインスタンス変数と異なりそのクラスから作られたオブジェクト全てで共通して利用できる変数です。
目次
クラス変数
インスタンス変数を定義する際はコンストラクタの処理として記述しましたが、クラス変数はそのまま記述します。
また、クラス変数はクラス内で参照する場合であっても次のようにクラス名を付けて記述します。
class クラス名: クラス変数名 = 値 # クラス変数を定義 def メソッド名(): print(クラス名.クラス変数名) # クラス変数を表示
例としてこれまでのコードにモンスターの合計攻撃力をカウントするクラス変数を追加してみましょう。
class Monster: total_ad = 0 # クラス変数を定義 def __init__(self, name, ad): self.name = name self.ad = ad Monster.total_ad += ad # オブジェクトのadを加算 def attack(self): print(self.name + "は" + str(self.ad) + "のダメージを与えた") monsters = [] monsters.append(Monster("デス・ナイト", 100)) monsters.append(Monster("ハムスケ", 30)) monsters.append(Monster("スケリトル・ドラゴン", 50)) for monster in monsters: monster.attack() print("合計" + str(Monster.total_ad) + "のダメージを与えた") # クラス変数を呼び出し
まずtotal_adというクラス変数を定義し、オブジェクトが生成されるたびにそのadをtotal_adに加算するコードをコンストラクタに追加します。
最後にtotal_adの中身を表示するコードを記述しておきましょう。
実行結果は次のようになります。
デス・ナイトは100のダメージを与えた ハムスケは30のダメージを与えた スケリトル・ドラゴンは50のダメージを与えた 合計180のダメージを与えた
各モンスターの攻撃が終わった後、その合計ダメージが表示されました。
このようにクラス変数はオブジェクトごとに値を持つのではなく、クラスで共通した値を持っています。
そのためオブジェクトに拠らない、クラス全体の情報を管理するのに役立ちます。
クラスメソッド
クラス変数と同様、オブジェクトに拠らないクラス全体の情報を処理するためのメソッドをクラスメソッドといいます。
先ほどの合計ダメージの出力コードはクラスの外部から呼び出していましたが、Monsterクラスの情報ですのでクラス内部でクラスメソッドにしてみましょう。
クラスメソッドを定義するには次のように記述します。
class クラス名: def クラスメソッド名(cls): # クラスメソッドを定義 処理 変数名 = classmethod(クラスメソッド名) # クラスメソッドを変数に代入 中略 クラス名.変数名() # クラスメソッドを呼び出し
クラスメソッドの引数となっているclsはクラス自体が入る引数です。インスタンスメソッドの引数にインスタンス自体が入るselfを記述するように、クラスメソッドには必ずクラス自体が入るcls引数を記述します。
classmethod関数は引数にクラスメソッドにしたい関数を渡すとクラスメソッドに変換して返してくれます。また、Pythonでは関数もオブジェクトなので変数に代入することができます。
最後にメソッドを呼び出す記述をしていますが、クラスメソッドはオブジェクトを作らなくても呼び出せます。
では実際に合計ダメージの出力コードをクラスメソッドとして記述してみましょう。
class Monster: total_ad = 0 def summary(cls): # クラスメソッドを定義 print("合計" + str(Monster.total_ad) + "のダメージを与えた") def __init__(self, name, ad): self.name = name self.ad = ad Monster.total_ad += ad def attack(self): print(self.name + "は" + str(self.ad) + "のダメージを与えた") summary = classmethod(summary) # クラスメソッドを変数に代入 monsters = [] monsters.append(Monster("デス・ナイト", 100)) monsters.append(Monster("ハムスケ", 30)) monsters.append(Monster("スケリトル・ドラゴン", 50)) for monster in monsters: monster.attack() Monster.summary() # クラスメソッドを呼び出し
実行結果は次のとおりです。
デス・ナイトは100のダメージを与えた ハムスケは30のダメージを与えた スケリトル・ドラゴンは50のダメージを与えた 合計180のダメージを与えた
先ほどの処理をクラスメソッドとしてクラス内に定義して、最後の行でクラスメソッドを呼び出して実行することができました。
ちなみにクラスメソッドは次のように記述して定義することもできます。
class Monster: total_ad = 0 @classmethod # デコレータでクラスメソッドに変換 def summary(cls): print("合計" + str(Monster.total_ad) + "のダメージを与えた") 後略
この@classmethodはPythonのデコレータという機能で、すでに定義されている関数に処理を追加することができます。
今回の場合はclassmethod関数によってメソッドをクラスメソッドにする処理をデコレータで追加しています。