Classmethod とは
classmethod
はPythonではクラスに属し、クラスのインスタンスではないメソッドを定義するために使用できるビルトインデコレータです。これは、クラスのインスタンスではなく、クラスそのものに対してclassmethod
を呼び出すことができることを意味します。
classmethod
の主な目的は、クラスが自身のクラスレベルの状態を変更またはアクセスできるようにすることです。これは、クラスの代替コンストラクタを作成するために便利であったり、クラスのインスタンスを返すファクトリメソッドを実装するために便利であったりします。
classmethod
を定義するには、メソッドの定義の前に@classmethod
デコレーターを追加する必要があります。メソッドの最初のパラメータはcls
であり、クラス自体を参照します。以下は例です。
class MyClass:
class_variable = 10
@classmethod
def class_method(cls, x):
return cls.class_variable * x
result = MyClass.class_method(5)
print(result) # Output: 50
この例では、class_variable
はクラスレベルの変数であり、class_method()
でアクセスおよび変更できます。 class_method()
はパラメータx
を取り、class_variable
と掛け合わせた結果を返します。
まとめると、classmethod
は、インスタンスではなくクラスに属するメソッドを定義することができるPythonの強力なツールであることがわかります。代替コンストラクタやファクトリメソッドの作成、クラスレベルの状態の変更やアクセスに一般的に使用されます。
Staticmethod とは
Pythonには、インスタンスやクラスレベルの状態にアクセスする必要がない場合に、クラスに属するメソッドを定義するための組み込みのstaticmethod
デコレータが用意されています。staticmethod
の使い方を示す例を紹介します。
人を表すPerson
クラスがあるとし、2つの日付を受け取り、その差を年数で返すメソッドを定義したいとします。このメソッドは、インスタンスやクラスレベルの状態にアクセスする必要がないため、staticmethod
の良い候補です。
import datetime
class Person:
def __init__(self, name, birthdate):
self.name = name
self.birthdate = birthdate
@staticmethod
def calculate_age(birthdate, today):
age = today.year - birthdate.year - ((today.month, today.day) < (birthdate.month, birthdate.day))
return age
person1 = Person("John", datetime.date(1990, 1, 1))
today = datetime.date.today()
age = Person.calculate_age(person1.birthdate, today)
print(f"{person1.name} is {age} years old.")
この例では、calculate_age
メソッドをstaticmethod
として定義しています。このメソッドは、birthdate
とtoday
の2つの日付を受け取り、シンプルなアルゴリズムを使用してそれらの差を年数で計算します。
次に、名前と誕生日を持つPerson
オブジェクトを作成し、datetime.date.today()
メソッドを使って現在の日付を取得します。Person
クラスのcalculate_age
メソッドを呼び出し、Person
オブジェクトの誕生日と現在の日付を渡して、年齢を取得しています。最後に、人の名前と年齢を出力します。
staticmethod
を使用することで、Person
クラスに属するメソッドを定義することができましたが、インスタンスやクラスレベルの状態にアクセスする必要がないため、コードがより整理され、読みやすくなります。
Classmethod と Staticmethod の比較
classmethod
とstaticmethod
は最初には似ているように見えますが、実際には2つの間にはいくつかの重要な違いがあります。
classmethod
は、クラス自体に対して、インスタンスではなくメソッドを操作する場合に使用されます。一般的に、cls
と呼ばれるクラスを最初の引数として取ります。これにより、クラスレベルの状態にアクセスし、必要に応じて新しいクラスのインスタンスを作成することができます。
一方、 staticmethod
は、クラスに属するが、特定のインスタンスに属するものではない場合に使用されます。これにはクラスを引数にとらず、クラスレベルの状態にアクセスすることはできません。これは、クラスに関連するユーティリティ関数によく使われますが、インスタンスレベルの状態にアクセスする必要がない場合に使用されます。
以下に、2つのメソッドの比較を示します。
-
シグネチャ
classmethod
はクラス自体を表すcls
パラメータを最初の引数として取ります。staticmethod
は特別なパラメータを取りません。
-
クラスレベルの状態にアクセスすることができるか
classmethod
はcls
パラメータを介してクラスレベルの状態にアクセスできます。staticmethod
はクラスレベルの状態にアクセスできません。
-
新しいインスタンスを作成することができるか
classmethod
はcls
パラメータを介してクラスの新しいインスタンスを作成できます。staticmethod
はクラスの新しいインスタンスを作成することができません。
-
継承
classmethod
はサブクラスに継承され、オーバーライドされる可能性があります。staticmethod
もサブクラスに継承されますが、オーバーライドすることはできません。
以下は、違いを説明する例です。
class MyClass:
class_var = "class variable"
def __init__(self, inst_var):
self.inst_var = inst_var
@classmethod
def from_class_method(cls, inst_var):
return cls(inst_var + " (created by classmethod)")
@staticmethod
def from_static_method(inst_var):
return MyClass(inst_var + " (created by staticmethod)")
instance = MyClass("instance variable")
instance2 = MyClass.from_class_method("instance variable")
instance3 = MyClass.from_static_method("instance variable")
print(instance.class_var) # "class variable"
print(instance2.class_var) # "class variable"
print(instance3.class_var) # "class variable"
print(instance.inst_var) # "instance variable"
print(instance2.inst_var) # "instance variable (created by classmethod)"
print(instance3.inst_var) # "instance variable (created by staticmethod)"
この例では、class_var
とinst_var
を持つMyClass
を定義しています。そして、クラスを生成するためのclassmethod
とstaticmethod
を定義しています。
from_class_method
メソッドを呼び出すと、指定されたinst_var
を持つ新しいクラスのインスタンスを作成して、それを返します。from_static_method
メソッドを呼び出すと、新しいクラスのインスタンスを作成して、それを返します。
出力からわかるように、両方のメソッドはクラス変数にアクセスできますが、classmethod
のみがクラスのインスタンスをアクセスして生成することができます。
参考