web-dev-qa-db-ja.com

クラス本体内でクラスstaticmethodを呼び出しますか?

クラスの本体内から静的メソッドを使用して、組み込み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):<br>
  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

だから私の質問は:

これを達成するためのよりクリーンなまたはより「Python的な」方法のように、より良い方法はありますか?

127
martineau

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は非常に役立ちます)は、これらの種類の質問を非常に迅速に解決できることがよくあります。

145
Ben

これは私が好む方法です:

class Klass(object):

    @staticmethod
    def stat_func():
        return 42

    _ANS = stat_func.__func__()

    def method(self):
        return self.__class__.stat_func() + self.__class__._ANS

DRY原則 のため、このソリューションはKlass.stat_funcよりも好みます。 新しいsuper()が存在する理由 Python 3を思い出します:)

しかし、私は他の人に同意します。通常、最良の選択はモジュールレベル関数を定義することです。

たとえば、@staticmethod関数を使用した場合、再帰はあまり良く見えない場合があります(Klass.stat_func内でKlass.stat_funcを呼び出すことでDRY原則を破る必要があります)。これは、静的メソッド内でselfへの参照がないためです。モジュールレベルの機能では、すべてが正常に見えます。

20
Jan Vorcak

これは、静的メソッドが記述子であるためであり、記述子プロトコルを実行して真の呼び出し可能オブジェクトを取得するには、クラスレベルの属性フェッチが必要です。

ソースコードから:

クラス(例:C.f())またはインスタンス(例:C().f())で呼び出すことができます。インスタンスはクラスを除いて無視されます。

ただし、クラスの定義中にクラス内から直接ではありません。

しかし、あるコメンターが言ったように、これは実際には「Python」設計ではありません。代わりにモジュールレベルの関数を使用してください。

9
Keith

クラス定義の後にクラス属性を注入するのはどうですか?

class Klass(object):

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

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

Klass._ANS = Klass.stat_func()  # inject the class attribute with static method value
8
Pedro Romano

このソリューションはどうですか? @staticmethodデコレータの実装の知識に依存しません。内部クラスStaticMethodは、静的初期化関数のコンテナとして再生されます。

class Klass(object):

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

    _ANS = StaticMethod._stat_func()  # call the staticmethod

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

以下のブログによると、クラス内の静的メソッドを呼び出す場合、呼び出し元関数はクラスメソッドである必要があるため、メソッド定義に@classmethodを追加すると問題が解決する場合があります。

Pythonで静的メソッド、クラスメソッド、または抽象メソッドを使用する方法に関する決定的なガイド

0
whimian