インスタンスメソッドとクラスメソッドについて

4.3 インスタンスメソッドとクラスメソッドについて

インスタンス変数とクラス変数について勉強してきましたが、実はメソッドにもインスタンスメソッド、クラスメソッドと呼ばれるものがあり、インスタンスを介してアクセスできるのか、クラスから直接アクセスできるのかによって分類できます。
ここではインスタンスメソッドとクラスメソッドについて説明していきます。

4.3.1 デコレータについて

インスタンスメソッドとクラスメソッドについて理解するためには、まずデコレータについて学ぶ必要があります。
デコレータとは、既存の関数(メソッド)の処理を引き継ぐためのもので、既存の関数(メソッド)の中身を直接変更せずに、機能の追加や変更を実現する上で便利なものです。

似たような処理をする関数を作る手間を省くために、デコレータが使われます。具体的にデコレータを実行する方法について確認していきましょう。

1. 一般的な書式

まずデコレータは、新しく定義する関数(デコレートされる関数)を介して、継承元となる既存の関数(デコレートする関数)の処理を実行します。
デコレータを実行するにあたり以下の2点が必要になります。

  • 既存の関数(デコレートする関数)に第一引数(func)を指定する
  • 新しい関数(デコレータされる関数)を定義する前の行で、「@デコレートする関数の名前」を記載する
  • 新しい関数を実行する際には、基本的には括弧( )は不要
書式

func1をデコレートする関数(既存の関数)、func2をデコレートされる関数(新しく定義される関数)として、書式をまとめると以下のようになります。

「( )」括弧をつけずにデコレートされる関数(func2)を読み込むと、func2は実行されず、func2自身を引数に、デコレートする関数(func1)が実行されます。
またデコレータする関数(func1)の引数は自由に指定できますが、当テキストではfuncで統一させていただきます。

凡例
    #デコレートする関数を定義
    def func1(func):
        print("func1")

    #func1の処理を加えるfunc2を定義
    @func1
    def func2():
        print(‘func2’)

    #func2を読み込む
    func2
	
実行結果
	func1
	

凡例からfunc2が読み込まれてますが、func2の処理は読み込まれず、そのままfunc1が実行されているのがわかります。

図 4.3.1:デコレータ

2. デコレータされる関数の処理を反映させた場合の書式

デコレータでは、新しく定義した関数(以下、func2を記載します。)そのものを引数に既存の関数(以下、func1と記載します。)の処理を実行しましたが、func2の処理の内容を反映させるにはどうすれば良いのでしょうか?

書式

func1は、func2を引数に処理が実行されるため、func1の処理内にfunc2を実行させる命令文を記載すれば、func2の内容は反映されます。
書式にまとめると以下の通りになります。

凡例
    #デコレートする関数を定義
    def func1(func):
        print("func1")
        #func2の処理を実行
        func()
    #func1の処理を加えるfunc2を定義
    @func1
    def func2():
        print("func2")

    func2
	
実行結果
	func1
	func2
	

func2が読み込まれていると同時に、func1が実行され、func1の引数としてfunc2が読み込まれているため、引数として指定したfunc()を命令文に記載すると、func1の処理を通じてfunc2が実行されます。
実行結果からfunc2の処理内容より、先にfunc1の処理内容が読み込まれ、その後、func1の処理内容が実行されているので、func1の処理の内容に沿った実行結果になっていることがわかります。

図 4.3.2:デコレータ②

4.3.2 インスタンスメソッドについて

以上がデコレータになります。続いて本題であるインスタンスメソッド、クラスメソッドに戻りたいと思います。

1. インスタンスメソッドとは

まずインスタンスメソッドとは、コンストラクタが定義されたクラス内において、インスタンス自身を紐づかせるためのメソッドです。
直接、アクセスすることはできず、インスタンスを生成した上で、インスタンスを介してアクセスすることができます。

今までコンストラクタを学習する上で扱ってきたメソッドそのものが、インスタンスメソッドに該当します。

2. インスタンスメソッドの定義方法

インスタンスメソッドを定義する際には、第一引数(以下、selfで統一します。)を指定しなければなりません。
selfにはインスタンス自身が引き渡されます。
インスタンスメソッドの定義方法をまとめると以下の書式の通りになります。

書式:インスタンスメソッドの定義方法
    class クラス名:
        def __init__(self,引数,..)
            self.インスタンス変数 = 引数
            …
        def インスタンスメソッド(self)
            処理内容
	

3. インスタンスメソッドへのアクセス方法

またインスタンスメソッドの呼び出しは、インスタンスを介して行われます。そのためインスタンスメソッドの定義方法をまとめると下記の書式の通りです。

書式:インスタンスメソッドへのアクセス方法
    インスタンス名 = クラス名
    インスタンス名.インスタンスメソッド名
	
凡例
    class Sample:

        def __init__(self,name):
            self.name = name
        def callName(self):
            print('名前:',self.name)

    sample1 = Sample("太郎")
    sample1.callName()
	
実行結果
	名前: 太郎
	

4.3.3 クラスメソッドについて

続いてクラスメソッドについて説明します。

1. クラスメソッドとは

各インスタンスに紐づかせるインスタンスメソッドに対して、クラスメソッドは、クラスそのものを紐づかせるためのメソッドです。
インスタンスメソッドは、インスタンスを介してアクセスすることができましたが、クラスメソッドは、クラスを介して直接、アクセスすることができます。

2. クラスメソッドの定義方法

クラスメソッドを定義するためには、以下の2点に従う必要があります。

  • メソッドの1行前に、デコレータである「@classmethod」と追記する
  • 第一引数(以下、clsに統一する)を従える

第一引数のclsには、メソッドを呼び出したときクラス自身が代入されます。引数名はclsである必要はありませんが、一般的にはclsを使用するので、clsを指定してあげるようにしましょう。
クラスメソッドの定義方法をまとめると以下の書式の通りになります。

書式
    class クラス名:
        def __init__(self,引数,..)
            self.インスタンス変数 = 引数
            …
        @classmethod
        def クラスメソッド(cls):
            処理内容
	

3. クラスメソッドへアクセスする方法

インスタンスメソッドと異なり、クラスメソッドはクラス自身に紐づいたメソッドですので、クラスから直接、呼び出すことができます。
またインスタンスを介して呼び出すことも可能です。書式をまとめると以下の通りです。

書式
    ①	クラス名.クラスメソッド名
    ②	インスタンス名.クラスメソッド名
	
凡例
    class Sample:

        def __init__(self,name):
            self.name = name

        @classmethod
        def clsMtd(cls):
            print('クラスメソッドの実行')

    #クラスから直接アクセス
    Sample.clsMtd()
    #インスタンスからアクセス
    sample1 = Sample('太郎')
    sample1.clsMtd()
	
実行結果
	クラスメソッドの実行
	クラスメソッドの実行
	

凡例のイメージをまとめると以下の図の通りになります。

図 4.3.3: クラスメソッドへのアクセス

4. クラスメソッド内で変数にアクセスする方法

「4.1.1インスタンス変数の特徴①:アクセス方法」でも説明した通り、インスタンス変数は、インスタンスそのものに紐づかせた変数であり、インスタンスメソッドから呼び出すことができます。
インスタンスメソッドの第一引数であるself自体が、インスタンスそのものを表すため、selfを介してインスタンス変数にアクセスすることができるからです。
またインスタンス変数だけではなくインスタンスメソッドからクラス変数を呼び出すこともできます。

一方、クラスメソッドは、クラスを紐づくメソッドですので、インスタンス変数を呼び出すことはできませんが、クラス変数にアクセスすることはできます。
クラスメソッドの第一引数であるclsが、クラスそのものを表すので、clsを介してクラス変数にアクセスできるからです。

書式:クラスメソッド内からクラス変数にアクセスする方法

ではクラスメソッド内でクラス変数にアクセスするにはどうすれば良いのでしょうか。「cls.クラス変数名」を記載することで、クラス変数にアクセスできます。
書式をまとめると以下の通りです。

    cls.クラス変数名
	
凡例
    class Sample:
        #クラス変数の宣言
        clsName = 'クラス変数'

        def __init__(self,name):
            self.name = name

        @classmethod
        def clsMtd(cls):
            #クラス変数の呼び出し
            return cls.clsName

    #クラスメソッドの実行
    print(Sample.clsMtd())
	
実行結果
	クラス変数
	

凡例のイメージをまとめると以下の図の通りになります。

図 4.3.4: クラスメソッドからクラス変数へのアクセス

4.3.4 インスタンスメソッドとクラスメソッドを使ったプログラム

続きまして、インスタンスメソッド、クラスメソッドを使ったプログラムを確認していきましょう。

ソース・フォルダー: /Desktop/Python基礎講座
ファイル名: 第4章.ipynb
アクセスURL: http://localhost:8888/notebooks/Desktop/Python基礎講座/第4章.ipynb

    class Computer:

        num = 0
        def __init__(self,name,memory):
            self.name = name
            self.memory = memory
            Computer.num += 1

        def osMemory(self):
            print('【作成されたPCの内容】')
            print('・os名:',self.name)
            print('・メモリー:',self.memory,'GB')

        @classmethod
        def checknum(cls):
            print('【メンテナンスチェック】')
            if cls.num > 2:
                print('作成台数は',cls.num,'台ですので、メンテナンスを実施します。')
            else:
                print('作成台数は',cls.num,'台です。メンテナンスは不要です。')

    #作成台数をチェック
    Computer.checknum()
    #PCの生成
    com1 = Computer('Windows',40)
    com1.osMemory()
    #作成台数をチェック
    Computer.checknum()
    #PCの生成
    com2 = Computer('Mac',100)
    com2.osMemory()
    #作成台数をチェック
    Computer.checknum()
    #PCの生成
    com3 = Computer('Windows',90)
    com3.osMemory()
    #作成台数をチェック
    Computer.checknum()
	

実行結果

	【メンテナンスチェック】
	作成台数は 0 台です。メンテナンスは不要です。
	【作成されたPCの内容】
	・os名: Windows
	・メモリー: 40 GB
	【メンテナンスチェック】
	作成台数は 1 台です。メンテナンスは不要です。
	【作成されたPCの内容】
	・os名: Mac
	・メモリー: 100 GB
	【メンテナンスチェック】
	作成台数は 2 台です。メンテナンスは不要です。
	【作成されたPCの内容】
	・os名: Windows
	・メモリー: 90 GB
	【メンテナンスチェック】
	作成台数は 3 台ですので、メンテナンスを実施します。
	

解説

1~20行目でComputerというクラスを定義しています。3行目ではクラス変数numを宣言しており、5~8行目でコンストラクタを定義してます。

コンストラクタでは、name、memoryと二つのインスタンス変数を宣言しており、また「Computer.num」によりクラス変数numを呼び出しており、numのインクリメント(変数の値を1つ足す)について記述しています。
クラス変数はインスタンス間で共有の値であり、インスタンスを生成するごとにコンストラクタ内部の処理が実行されるので、インスタンスが生成される度に、numの値が一つずつ増えていきます。

9~12行目では「osMemory」というインスタンスメソッドが定義されてます。こちらのメソッドでは、インスタンス変数のnameとmemoryを出力する処理を行います。

14~20行目では「checknum」というクラスメソッドを定義してます。checknumでは、クラス変数numを呼び出しており、numの値が2より大きい場合と小さい場合で、条件分岐により処理の内容を変えてます。

22~38行目では、クラスメソッドのchecknumの呼び出し、クラスComputerからインスタンスの生成、生成したインスタンスからインスタンスメソッドの呼び出しを、計3回行っています。

クラス変数numは、コンストラクタでインクリメントが記載されているので、23行目で参照すると0が出力されましたが、最終的には3つインスタンスを作成したので、3が出力されるようになります。


NEXT>> 4.4 本章のまとめ