204

クラスの本体内から静的メソッドを使用しようとすると、次の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」な方法はありますか?

4

6 に答える 6

226

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

于 2012-10-03T23:24:28.450 に答える
36

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

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のため、私はこのソリューションを よりも好みます。Python 3に new がある理由を思い出します:)super()

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

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

于 2014-12-10T16:42:26.537 に答える
12

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

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
于 2012-10-03T23:21:05.120 に答える
12

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

ソースコードから:

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

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

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

于 2012-10-03T23:40:18.797 に答える