<Python> staticmethod, classmethod, instancemthod

スタティックメソッド staticmethod
クラスメソッド classmethod
インスタンスメソッド instancemethod
と3種類あるらしい。

何が違って、何がうれしいのか、、、難い、、

これを見つけた。
staticmethodはなんとなくわかった。
これは単純にファンクションfunctionっぽい。
継承inheritanceした場合、継承先で同じ名前でオーバーライト可能。

julien.danjou.info

classmethodはこちらにいい例があった。

Life of a Computer Scientist: Really Understanding Python @staticmethod and @classmethod

クラス変数を呼び出す時がミソっぽい。

ちと同じことしてみた。

まずはstaticmethodで。

In [1]: class aaa():
   ...:     x = 1
   ...:     y = 2
   ...:     @staticmethod
   ...:     def plus():
   ...:         return x + y
   ...:     

In [2]: aaa.plus
Out[2]: <function __main__.aaa.plus>

In [3]: aaa.plus()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-3-94dbd059c682> in <module>()
----> 1 aaa.plus()

<ipython-input-1-6427408109ac> in plus()
      4     @staticmethod
      5     def plus():
----> 6         return x + y
      7 

NameError: name 'x' is not defined

クラス変数xにアクセスできず、、、
アクセスするには、次のようにクラスから呼び出す必要あり。

In [4]: class aaa():
   ...:     x = 1
   ...:     y = 2
   ...:     @staticmethod
   ...:     def plus():
   ...:         return aaa.x + aaa.y
   ...:     

In [5]: aaa.plus()
Out[5]: 3

で、classmethodの場合。
特定のクラス名aaaの代わりに一般名称のclsを使える。
クラス名aaaをハードコードhard codeしなくて済む。

In [6]: class aaa():
   ...:     x = 1
   ...:     y = 2
   ...:     @classmethod
   ...:     def plus(cls):
   ...:         return cls.x + cls.y
   ...:     

In [7]: aaa.plus()
Out[7]: 3

なので継承時が楽。

In [8]: class AAA(aaa):
   ...:     z = 3
   ...:     @staticmethod
   ...:     def show_z():
   ...:         return AAA.z
   ...:     

In [9]: AAA.plus()
Out[9]: 3


In [10]: aaa.plus
Out[10]: <bound method aaa.plus of <class '__main__.aaa'>>

なるほど。
ちとわかった気がする。


続き

staticmethodclassmethod で継承された時に、
継承先で元のメソッドを呼べるか? やってみた。

まずはclassmethod

In [30]: class bbb():
    ...:     @classmethod
    ...:     def x(cls):
    ...:         return 'hage'
    ...:     

In [31]: class BBB(bbb):
    ...:     @classmethod
    ...:     def x(cls):
    ...:         return 'Turu'
    ...:     

In [32]: bbb.x()
Out[32]: 'hage'

In [33]: BBB.x()
Out[33]: 'Turu'

ちゅう感じで継承先で同じ名前のメソッド作ったらオーバーライトされる。
でもsuper()を使って、、、

In [34]: class BBB(bbb):
    ...:     @classmethod
    ...:     def x(cls):
    ...:         return 'Turu'
    ...:     @classmethod
    ...:     def y(cls):
    ...:         return super(BBB, cls).x
    ...:     

In [35]: BBB.y()
Out[35]: <bound method bbb.x of <class '__main__.BBB'>>

ということなので、おりゃっと()をも一回やってみたら、、、

In [40]: BBB.y()()
Out[40]: 'hage'

元のメソッドが呼び出せたっぽい。
へー。

staticmethodの場合は、super()の引数にclsを持ってこれないから、
継承元のメソッドは呼び出せないかな、、、たぶん。