はじめに #
Pythonのクラスにおいて、インスタンスメソッドとクラスメソッド (classmethod
), スタティックメソッド (staticmethod
) を使い分ける方法をまとめました。以下のように使い分けます。
- インスタンスメソッド:インスタンス変数にアクセスする
- クラスメソッド:インスタンス変数にアクセスせず、クラス変数にアクセスする
- スタティックメソッド:インスタンス変数とクラス変数のどちらもアクセスしない
詳細は以下で述べます。
検証環境:Python 3.9.7
メソッドの使い分け #
まず各メソッドの使い分けについて、以下のMyClass
クラスを例に示します。
class MyClass:
CONST = 10 # クラス変数
def __init__(self, x):
self.x = x # インスタンス変数
def add0(self, y, z):
# インスタンスメソッド
return self.x + y + z
@classmethod
def add1(cls, y, z):
# クラスメソッド
return cls.CONST + y + z
@staticmethod
def add2(y, z):
# スタティックメソッド
return y + z
x
はインスタンスごとに設定される変数で、インスタンス変数と呼びます。また、CONST
はMyClass
自体に設定されるので、クラス変数と呼びます。
add0
メソッドのようにインスタンス変数にアクセスするメソッドは、インスタンスメソッドとして定義します。インスタンスメソッドの第1引数には、self
を取ります。self
はインスタンス自身を指す変数です(慣習的にself
を使っているだけで、Pythonの予約語ではありません)。
一方、add1
メソッドのようにインスタンス変数は使用せず、クラス変数にのみアクセスするものは、@classmethod
を付けて、クラスメソッドとして定義します。クラスメソッドの第1引数には、cls
を取ります。cls
はクラス自身を指す変数です(こちらも慣習的にcls
を使っているだけで、Pythonの予約語ではありません)。
最後に、add2
メソッドのように、インスタンス変数もクラス変数も使用しないものは、@staticmethod
を付けて、スタティックメソッドとして定義します。スタティックメソッドの引数には、必要な変数のみ定義します。
なお、__init__
はインスタンスの生成時に実行されるメソッドで、コンストラクタと呼びます。また、@classmethod
や@staticmethod
は関数を装飾する仕組みであり、デコレータと呼びます。
クラスメソッド #
各インスタンスはクラス変数にアクセスできるため、クラスメソッドは以下のようにインスタンスメソッドとして記述することも出来ます。
def add1(self, y, z):
return self.CONST + y + z
ただし、インスタンス変数にアクセスしない(インスタンス変数を変更しない)ことを明示するには、最初の例のように@classmethod
を付けた方が良いでしょう。
スタティックメソッド #
一方、スタティックメソッドとして定義可能なメソッドは、以下のようなインスタンスメソッドとして書くことも可能です。
def add2(self, y, z):
return y + z
しかし、PyLintで構文チェックを掛けると、以下のリファクタリングのメッセージが出力されます。
R0201 (no-self-use) Method could be a function
すなわち、「メソッドは関数として定義できる」という意味です。クラスの外にadd2
メソッドを出してもロジック上は問題ないのですが、MyClass
クラスの他のメソッドからadd2
を呼び出している場合などは、クラスから出したくないこともあります。
そこで@staticmethod
を付け、スタティックメソッドとして定義することで、PyLintのメッセージを出力しないようにできます。
また、@staticmethod
を付けたご利益として、以下のようにインスタンスを定義せずにメソッドを使用できます。
>>> MyClass.add2(1, 2)
3
もしadd2
をインスタンスメソッドとして定義すると、以下のように一度インスタンスを作った上でメソッドを実行する必要があります。
>>> my_class = MyClass(3)
>>> my_class.add2(1, 2)
3