Pythonにはclassmethodとstaticmethodという似たような二種類のメソッドがあるが、どっちを使うべきなのか?と思ったので調べた
メソッドの書き方
classmethodの場合
@classmethod
def increment_classmethod(cls, value):
return value + 1
staticmethodの場合
@staticmethod
def increment_staticmethod(value):
return value + 1
違いはclassmethodの場合は第一引数がcls
になるのに対して、staticmethodは純粋に引数から始まります
なのでclassmethodでcls.hoge
でクラスのプロパティやメソッドにアクセスできます、ただA.hoge
やるのと大差ないかなと思います
メソッドの呼び方
class A:
@staticmethod
def increment(value):
return value + 1
@classmethod
def increment_classmethod(cls, value):
return cls.increment(value)
@staticmethod
def increment_staticmethod(value):
return A.increment(value)
このようなクラスがある場合、外から呼ぶ場合はどちらも呼び方は同じです
A.increment_classmethod(value)
A.increment_staticmethod(value)
ただし、同じクラス内で呼ぶ場合は、classmethodの場合第一引数がcls
なので
cls.increment(value)
と呼ぶことができます
また、継承した場合はちょっと変わってきます
以下のように継承したクラスの場合
class B:
@staticmethod
def increment(value):
return value + 1
@classmethod
def increment_classmethod(cls, value):
return cls.increment(value)
@staticmethod
def increment_staticmethod(value):
return B.increment(value)
class A(B):
@staticmethod
def increment(value):
return value + 2
value = A.increment_classmethod(1)
print('classmethod:' + str(value))
value = A.increment_staticmethod(1)
print('staticmethod:' + str(value))
結果
classmethod:3
staticmethod:2
classmethodから呼ぶ場合は、cls.increment
で呼ぶことによりサブクラスのincrement
が呼ばれますが
staticmethodから呼ぶ場合は、クラス名を指定する必要があるので、オーバーライドしてようがそのクラスのincrement
が呼ばれます
速度
classmethodは第一引数にclsを入れる処理の分staticmethodよりも遅いらしいので計測してみました
import time
class A:
@staticmethod
def increment(value):
return value + 2
@classmethod
def increment_classmethod(cls, value):
return cls.increment(value)
@staticmethod
def increment_staticmethod(value):
return A.increment(value)
start_time = time.time()
value = 1
for i in range(0, 1000000):
value = A.increment_classmethod(value)
end_time = time.time()
print('classmethod:' + str(end_time - start_time) + '秒')
start_time = time.time()
value = 1
for i in range(0, 1000000):
# value = A.increment_classmethod(value)
value = A.increment_staticmethod(value)
end_time = time.time()
print('staticmethod:' + str(end_time - start_time) + '秒')
こんな感じで10回計測してみます
paizaで計測しました
結果
classmethod平均:0.2170754433秒
staticmethod平均:0.2145765066秒
確かにstaticmethodの方が少し早いですが、気にするレベルじゃないと思います
結論
- クラス名書くより、
cls.
で書いた方が楽 - 継承した際にオーバーライドできる
- 速度的には気にするほどではない
という点から基本classmethod使ってれば問題ないかなと思いました