クラスの本体内から静的メソッドを使用して、組み込み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的な」方法のように、より良い方法はありますか?
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
は非常に役立ちます)は、これらの種類の質問を非常に迅速に解決できることがよくあります。
これは私が好む方法です:
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
への参照がないためです。モジュールレベルの機能では、すべてが正常に見えます。
これは、静的メソッドが記述子であるためであり、記述子プロトコルを実行して真の呼び出し可能オブジェクトを取得するには、クラスレベルの属性フェッチが必要です。
ソースコードから:
クラス(例:
C.f()
)またはインスタンス(例:C().f()
)で呼び出すことができます。インスタンスはクラスを除いて無視されます。
ただし、クラスの定義中にクラス内から直接ではありません。
しかし、あるコメンターが言ったように、これは実際には「Python」設計ではありません。代わりにモジュールレベルの関数を使用してください。
クラス定義の後にクラス属性を注入するのはどうですか?
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
このソリューションはどうですか? @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
以下のブログによると、クラス内の静的メソッドを呼び出す場合、呼び出し元関数はクラスメソッドである必要があるため、メソッド定義に@classmethod
を追加すると問題が解決する場合があります。