【Pythonを使い倒す】クラス変数とクラスメソッドとは?クラス変数とインスタンス変数の組み合わせて機能的なコードが書けるようになろう!

前回の記事では、コンストラクタ(イニシャライザ)を活用してキレイなコードの書き方について解説をしました。今回はクラス変数とクラスメソッドを解説します。

クラス変数とクラスメソッド

クラス変数を用いることで、クラス自体が値を保持できるようになります。
また、クラスメソッドはクラス名から直接呼び出すことができます。

クラス内で変数を定義

以下の例では、クラス内で変数を定義しています。
このような変数は、クラス変数と呼ばれ、
クラス変数は、クラス名を使ってアクセス可能で、クラス自体に値が保持されます。

クラス内で変数を定義
class Fruit1:
    apple = "Apple" # クラス変数
    banana = "Banana" # クラス変数
    
print(Fruit1.apple) # クラス変数にアクセス

Fruit1.apple = "りんご" # クラス変数の値を変更
print(Fruit1.apple)
実行結果

Apple
りんご

解説:
こちらのセルのコードを見ていきましょう。
Fruit1クラスの中で変数が2つ定義されています。
変数appleと変数bananaにそれぞれ文字列が入っていますね。

このようにしてクラスの中で定義された変数をクラス変数と言います。
クラス変数はクラス名からアクセスすることができます

ここではクラス変数をappleにアクセスするためにクラス名の後にappleと書いています。
appleの値をプリントした後にappleに”りんご”という文字列を入れています。
このようにクラス変数の値を変更することができ、変更した後にこの値をプリントします。

実行結果から”Apple りんご”と表示されたことがわかります。

クラス変数にアクセスし、クラス変数の値を変更することができました。

クラスメソッドを定義

またクラス名から呼び出すことのできるメソッドを、クラスメソッドといいます。
クラスメソッドを定義する際は、メソッド名の前に@classmethodと記述します。
クラスメソッドは、クラス自体を表すclsを引数として受け取りますが、これを用いてクラス変数にアクセスすることができます。

クラスメソッドを定義
class Fruit2:
    apple = "Apple"
    banana = "Banana"
    
    @classmethod # この記述があるとクラスメソッド
    def sayAP(cls): # clsはクラス自体
        print(cls.apple, cls.banana) # クラス変数にアクセス
    
Fruit2.sayAP() # クラスメソッドを呼び出す
実行結果

Apple Banana

解説:
こちらのセルのコードを見ていきましょう。
クラスFruit2ではAppleとbananaというクラス変数が設定されています。

その後にsayAP()というメソッドが定義されていますが、その前に@classmethodと書いてあります。
この記述があるとその後のメソッドがクラスメソッドになり、クラスメソッドはclsを引数として受け取ります。
このclsはクラス自体です。
そしてclsを用いてクラス変数にアクセスすることができ、クラスメソッドを呼び出す際はクラス名から直接呼び出します。
このようにしてクラスFruit2のsayAP()メソッドを呼び出しています。

そして、実行結果はクラスメソッドが呼び出されてクラス変数の値がプリントされています。

以上のようなクラス変数やクラスメソッドを用いることで、インスタンスを生成しなくても手軽にクラスの機能を使うことができます。

それではクラスを実装する手順を以下にまとめておきます。

  1. クラス変数およびクラスメソッドを含むクラスを好きなように記述
  2. クラス変数の値を変更して、実際に変更されたことを確認してみる
  3. クラスメソッドを呼び出してみよう
  4. クラス変数とインスタンス変数の違いを考えてみよう

クラス変数およびクラスメソッドを1から実装してみてくださいね。

クラス変数とインスタンス変数

では、インスタンス変数や通常のメソッドとの違いをこれからご説明します。
※そもそもインスタン変数って何?という方はこちらの記事にて紹介しています。

Pythonのクラス変数とインスタンス変数には少々癖があります。
しかしながら、クラス変数とインスタンス変数をうまく組み合わせれば、クラスをより機能的に活用できるようになります。

クラス変数を定義して、インスタンス変数にアクセス

以下の例では、クラスFruit3内でクラス変数を定義しています。
しかしながら、インスタンス変数は設定されていません。
このようなケースでインスタンス変数にアクセスすると、エラーにならずにクラス変数の値を取得します。

クラス変数を定義して、インスタンス変数にアクセス
class Fruit3:
    apple = "Apple" # クラス変数を定義
    banana = "Banana"
        
p1 = Fruit3()
print(p1.apple) # インスタンス変数にアクセス エラーにならずにクラス変数の値を取得
実行結果

Apple

解説:
こちらのセルのコードを見ていきましょう。
クラスFruit3には Apple と banana という2つのクラス変数が定義されています。
クラスFruit3からインスタンスを生成してappleという名前のインスタンス変数にアクセスしようとすると、エラーにならずに同じ名前のクラス変数の値を取得します。
上記のように実行結果は Apple と表示されました。
インスタンス変数の設定がされていない場合、インスタンス変数にアクセスしようとするとクラス変数の値を取得することがわかります。

上記のケースで、その後インスタンス変数の値を変更してもクラス変数の値は変更されません。

インスタンス変数の値を変更した場合のクラス変数への影響

以下の例では、インスタンス変数appleの値を変更していますが、クラス変数は影響を受けていません。

インスタンス変数の値を変更した場合のクラス変数への影響
class Fruit4:
    apple = "Apple"
    banana = "Banana"
        
p2 = Fruit4()
p2.apple = "りんご" # インスタンス変数の値を変更
print(p2.apple) # インスタンス変数にアクセス

print(Fruit4.apple) # クラス変数にアクセス
実行結果

りんご
Apple

解説:
こちらのセルのコードではクラスFruit4に apple と banana というクラス変数が設定されています。
Fruit4からインスタンスを生成してappleに”りんご”という文字列を代入します。
このインスタンス変数をappleにアクセスしてプリントします。
その後に元のクラス変数のappleにアクセスしてプリントします。
実行すると上記の実行結果のように、りんごとappleと表示されました。
このような場合インスタンス変数の値を変更してもクラス変数の値は変更されませんね。

すなわち、クラス変数と同名の新たなインスタンス変数が作成されたことになります。

クラス変数とインスタンス変数を組み合わせる

以上を応用して、クラスを次のように書くことができます。
コードを短くまとめることができて、不用意にインスタンス変数にアクセスしてエラーを起こすこともありません。

クラス変数とインスタンス変数を組み合わせる
class Fruit5:
    fruits = "apples"
    number = 0
    
    def getFruits(self):
        return "I have " + str(self.number) + " " + self.fruits + "."
        
p3 = Fruit5()
print(p3.getFruits())

p3.fruits = "Bananas"
p3.number = 3
print(p3.getFruits())
実行結果

I have 0 apples.
I have 3 Bananas.

解説:
こちらのセルのコードではクラスFruit5の中に2つのクラス変数があります。
fruitsには”apples”という文字列が入っていて、numberには0という整数が入っています。

また、getFruits()という名前のメソッドがあります。
こちらのメソッドは文字列を結合して返します。

numberは文字列に変換して結合し、fruitsはそのまま結合します。
インスタンス変数に self を使ってアクセスしていますね。

このクラスFruit5からインスタンスを生成し、getFruits()メソッドを呼び出します。
その後にfruitsを”Bananas”に変更し、numberを3に変更、その後再びgetFruits()メソッドを呼び出します。

実行すると上記のような結果が表示されました。

最初にgetFruits()が呼ばれた際はクラス変数の値をインスタンス変数としてアクセスして用いましたが、その後にインスタンス変数の値を設定しなおして、再びgetFruits()メソッドを呼び出しました。
このようにクラス変数とインスタンス変数を組み合わせることで短く機能的なコードを書くことができます。

それでは最後にクラス変数とインスタンス変数を組み合わた実装手順をまとめておきます。

  1. クラス変数を含むクラスを好きなように書いてみよう
  2. クラスからインスタンスを生成し、クラス変名と同名のインスタンス変数にアクセスしてみよう
  3. クラス内にメソッドを記述し、クラス変数の値を返り値として取得してみよう

今回の内容は少々複雑でしたが何度かコードを変えて慣れていただければと思います。
今回はクラス変数とクラスメソッドの解説、及びインスタンス変数との組み合わせを解説しました。
クラスをうまく使って機能的なコードが書けるようになりましょう。