1. ホーム
  2. python

[解決済み】クラスのstaticmethodをクラス本体内で呼び出す?

2022-04-11 08:22:24

質問

クラス本体からスタティック・メソッドを使用しようとし、そのスタティック・メソッドを組み込みの staticmethod 関数をデコレータとして使用すると、このようになります。

class Klass(object):

    @staticmethod  # use as decorator
    def _stat_func():
        return 42

    _ANS = _stat_func()  # call the staticmethod

    def method(self):
        ret = Klass._stat_func() + Klass._ANS
        return ret

以下のようなエラーが発生します。

Traceback (most recent call last):
  File "call_staticmethod.py", line 1, in <module>
    class Klass(object): 
  File "call_staticmethod.py", line 7, in Klass
    _ANS = _stat_func() 
  TypeError: 'staticmethod' object is not callable

なぜこのようなことが起こるのか理解できた(ディスクリプターバインディング) を手動で変換することで、回避することができます。 _stat_func() を最後に使用した後、次のように staticmethod に変換します。

class Klass(object):

    def _stat_func():
        return 42

    _ANS = _stat_func()  # use the non-staticmethod version

    _stat_func = staticmethod(_stat_func)  # convert function to a static method

    def method(self):
        ret = Klass._stat_func() + Klass._ANS
        return ret

そこで質問なのですが。

これを達成するための、よりクリーンな、あるいはより "Pythonic" な方法はあるのでしょうか?

どのように解決するのですか?

staticmethod オブジェクトは、どうやら __func__ 属性に、元の生の関数が格納されます(そうしなければならなかったことは理にかなっています)。だから、これはうまくいくだろう。

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    _ANS = stat_func.__func__()  # call the staticmethod

    def method(self):
        ret = Klass.stat_func()
        return ret


余談ですが、staticmethodオブジェクトには、元の関数を保存する何らかの属性があるのではないかと思っていましたが、具体的なことは分かりませんでした。魚を与えるのではなく、釣りを教えるという精神で、私が調査してそれを見つけるために行ったことです(PythonセッションからのC&P)。

>>> class Foo(object):
...     @staticmethod
...     def foo():
...         return 3
...     global z
...     z = foo

>>> z
<staticmethod object at 0x0000000002E40558>
>>> Foo.foo
<function foo at 0x0000000002E3CBA8>
>>> dir(z)
['__class__', '__delattr__', '__doc__', '__format__', '__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> z.__func__
<function foo at 0x0000000002E3CBA8>

対話型セッションでの同様の掘り起こし( dir このような疑問は、すぐに解決できることが多いです。