インスタンス状態の情報を必要とするデコレータ関数を使用するpythonクラスを記述しようとしています。これは意図したとおりに機能していますが、明示的にデコレータを静的メソッドにすると、次のエラー:
Traceback (most recent call last):
File "tford.py", line 1, in <module>
class TFord(object):
File "tford.py", line 14, in TFord
@ensure_black
TypeError: 'staticmethod' object is not callable
どうして?
これがコードです:
class TFord(object):
def __init__(self, color):
self.color = color
@staticmethod
def ensure_black(func):
def _aux(self, *args, **kwargs):
if self.color == 'black':
return func(*args, **kwargs)
else:
return None
return _aux
@ensure_black
def get():
return 'Here is your shiny new T-Ford'
if __name__ == '__main__':
ford_red = TFord('red')
ford_black = TFord('black')
print ford_red.get()
print ford_black.get()
そして、もし私が行を削除した場合@staticmethod
、すべてが機能しますが、理由がわかりません。最初の引数としてself
が必要ではないでしょうか?
これは、staticmethod
の使用法ではありません。 staticmethod
オブジェクトは descriptors であり、ラップされたオブジェクトを返すため、classname.staticmethodname
としてアクセスした場合にのみ機能します。例
class A(object):
@staticmethod
def f():
pass
print A.f
print A.__dict__["f"]
プリント
<function f at 0x8af45dc>
<staticmethod object at 0x8aa6a94>
A
のスコープ内では、常に呼び出し可能な後者のオブジェクトを取得します。
デコレータをモジュールスコープに移動することを強くお勧めします。これはクラス内に属していないようです。クラス内に保持したい場合は、staticmethod
にせず、単にクラス本体の最後にdel
を付けます。外部から使用するためのものではありません。この場合のクラス。
Pythonクラスは、クラス宣言の内容を評価した後、実行時に作成されます。クラスは、宣言されたすべての変数と関数を特別なディクショナリに割り当て、そのディクショナリを使用してtype.__new__
を呼び出すことで評価されます( カスタマイズのクラス作成 を参照) 。
そう、
class A(B):
c = 1
以下と同等です。
A = type.__new__("A", (B,), {"c": 1})
@staticmethodを使用してメソッドに注釈を付けると、type.__new__
を使用してクラスが作成された後に発生する特別な魔法があります。クラス宣言スコープ内では、@ staticmethod関数は静的メソッドオブジェクトの単なるインスタンスであり、呼び出すことはできません。デコレータはおそらく、同じモジュールのクラス定義の上で宣言する必要がありますOR別の「デコレート」モジュール内(使用しているデコレータの数によって異なります)。一般に、デコレータはクラス。1つの注目すべき例外は、プロパティクラスです( properties を参照)。クラス宣言内にデコレータがあることは、色のクラスのように:
class Color(object):
def ___init__(self, color):
self.color = color
def ensure_same_color(f):
...
black = Color("black")
class TFord(object):
def __init__(self, color):
self.color = color
@black.ensure_same_color
def get():
return 'Here is your shiny new T-Ford'
今日、静的メソッドデコレータをクラス内でのみ使用することを望みました。
問題は、デコレータとして使用されようとしている静的メソッドは、実際には静的メソッドオブジェクトであり、呼び出し不可能であることです。
Solution:staticmethod object has method __get__
これは引数を取り、実際のメソッドを返します: python documentation Python 3.5以上:
class StaticMethod(object):
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
return self.f
私が付いてきた最小の解決策は:
class A():
def __init__(self):
self.n = 2
@staticmethod
def _addtoglobaltime(func):
from functools import wraps
@wraps(func)
def wrapper(*args, **kwargs):
self = args[0]
response = func(*args, **kwargs)
return self.n, response
return wrapper
@_addtoglobaltime.__get__('this can be anything')
def get(self):
return self.n**2
if __name__ == '__main__':
a = A()
print(a.get())
印刷します(2、4)