本やUdemy、Progateなどを用いてPythonやhtml、cssの学習過程を残していきます。

Pythonのインスタンスメソッドとクラスメソッド、スタティックメソッドの違いについて

Pythonのクラスにおいては”インスタンスメソッド”、”クラスメソッド”、”スタティックメソッド”と3つのメソッドで関数を定義することができるのですが、その3つの使い方が厄介だったので理解した事をメモしておきます。

※Jupyer labを使用している為、面倒くさくてprint()は使用しておりません。

クラス変数の説明

インスタンス変数について簡単に説明

以下のコードの様に、インスタンスが生成されるとデータが作成される変数をインスタンス変数と言いました。

class ins():
    def __init__(self):
        self.name = "インスタンス名前"
        self.age = "インスタンス年齢"
        self.sex = "インスタンス性別"

インスタンス変数の出力

i = ins()
i.name
>>>'インスタンス名前'

i.age
>>>'インスタンス年齢'

i.sex
>>>'インスタンス性別'

クラス変数の説明

上のインスタンス変数に対して、クラス変数はインスタンスを作らなくてもアクセスできる変数です。

クラス直下に変数を定義する事でクラス変数を定義することができます。

class cls():
    cls_str = "クラス文字"

    def __init(self): 
        self.name = "インスタンス名前" 
        self.age = "インスタンス年齢" 
        self.sex = "インスタンス性別"

クラス変数にアクセスする際は、クラス名.変数名 でアクセスできます。

cls.cls_str
>>>'クラス文字'

また、クラス名.変数名 = 代入 という形でクラス変数への上書きが可能です。

cls.cls_str = "上書きしました"
cls.cls_str
>>>'上書きしました'

気をつけなければならないのが、インスタンス変数と違い、クラス変数はそのクラスに関わる全てのオブジェクトに影響を及ぼしてしまうことです

class cls():
    cls_str = "クラス文字"

    def __init(self): 
        self.name = "インスタンス名前" 
        self.age = "インスタンス年齢" 
        self.sex = "インスタンス性別"

    @classmethod 
    def get_clsstr(cls): 
        return cls.cls_str
c1 = cls()
c1.cls_str
>>>'クラス文字'

cls.cls_str = "変更しました"
cls.cls_str
>>>'変更しました'

c1.cls_str
>>>'変更しました'

また、インスタンス.インスタンス変数 = 代入 という形で代入すると、新しくインスタンス変数が作成される事にも注意が必要です。

c2 = cls()
c2.cls_str
>>>'変更しました'

c2.cls_str = "newインスタンス文字"
c2.cls_str
>>>'newインスタンス文字'

c2.get_clsstr()
>>>'変更しました'

インスタンスメソッドとクラスメソッド、スタティックメソッドを作成して比較してみる。

以下、同じ動きをする様にインスタンスメソッド、クラスメソッド、スタティックメソッドを作成しました。

インスタンスメソッド

class Test_ins():
    s = "変更前"
    def __init__(self): 
        self.x = 5 

    def get_s(self): 
        return Test_ins.s 

    def set_s(self): 
        Test_ins.s = "へんこうしました" 

    def get_x(self): 
        return self.x

インスタンスメソッドは第一引数としてインスタンス(self)を受け取ります。

なので呼び出す際は Test_ins()のインスタンスが必要になります。

#インスタンスメソッドの呼び出し
Test_ins().get_s()
>>>'変更前'

Test_ins().set_s()
Test_ins().get_s()
>>>へんこうしました'

Test_ins().get_x()
>>>5

クラスメソッド

クラスメソッドはクラス関数の前に @classmethod を宣言して、引数に cls を指定します。

class Test_cls():
    s = "変更前"
    def __init__(self): 
        self.x = 5 

    @classmethod 
    def get_s(cls): 
        return cls.s 

    @classmethod 
    def set_s(cls): 
        cls.s = "へんこうしました" 

    @classmethod 
    def get_x(cls): 
        t = cls() 
        return t.x

クラスメソッドは第一引数として、クラスオブジェクト(cls)を受け取ります。

その為、インスタンスを作らずともアクセスすることができます。

しかし、インスタンスされていない為、インスタンス変数を取得することができず get_x()メソッド内でインスタンスを作り、インスタンスメソッドを作っています。

#クラスメソッドの呼び出し
Test_cls.get_s()
>>>'変更前'

Test_cls.set_s()
Test_cls.get_s()
>>>へんこうしました'

Test_cls.get_x()
>>>5

別でインスタンスを作成した場合、

インスタンスからget_x()関数にアクセスして上書きをしても、get_x()関数は別のインスタンスを参照している為、5が返ってきます。

tc = Test_cls()
tc.x = 100
tc.get_x()
>>>5

tc.x
>>>100

スタティックメソッド

スタティックメソッドはクラス関数の前に @staticmethod を宣言して、引数が無くても動作します。

引数を入れる際は通常の関数と同じ様に指定します。

class Test_sta():
    s = "変更前"
    def __init__(self): 
        self.x = 5 

    @staticmethod 
    def get_s(): 
        return Test_sta.s 

    @staticmethod 
    def set_s(): 
        Test_sta.s = "へんこうしました" 

    @staticmethod 
    def get_x(): 
        t = Test_sta() 
        return t.x

スタティックメソッドもクラスメソッドと同様にインスタンスを作らずともアクセスが可能です。

#スタティックメソッドの呼び出し
Test_sta.get_s()
>>>'変更前'

TTest_sta.set_s()
Test_sta.get_s()
>>>へんこうしました'

Test_sta.get_x()
>>>5

クラスメソッドと同様に別でインスタンスを作成した場合、

インスタンスからget_x()関数にアクセスして上書きをしても、get_x()関数は別のインスタンスを参照している為、上書きした値では無く5が返ってきます。

ts = Test_sta()
ts.x = 100
ts.get_x()
>>>5

ts.x
>>>100

クラスメソッドがあるなら、スタティックメソッドはいらなくないか?

クラスメソッドは第一引数にクラスが渡され、その渡ってきたクラスでクラス変数にアクセスできる。尚、インスタンス変数にはアクセスできない。

スタティックメソッドは毎回クラス宣言をしないとクラスにアクセスできない。
尚、インスタンス変数にはアクセスできない。

ここで、スタティックメソッドの使い所はあるのか? という疑問が浮かんできました。

で、一旦今の落とし所としてこちら「スタティックメソッドは要らない子?」を参考にさせて頂き、入門者はとりあえず使う場面は来ないだろうという結論を出し一旦忘れる事にしました。

また、スタティックメソッドじゃないと絶対ダメ!という場面が出てきたら追加します。

PS: クラス変数など何かクラスの情報を使うコードを書く場合はクラスメソッドを使って、それ以外はスタティックメソッドを使うと良いらしいです。

この記事を書いた人

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です