作为静态方法的Python装饰器
我正在尝试编写一个python类,它使用需要实例状态信息的decorator函数。这是按预期工作的,但如果我显式地将装饰器设置为staticmetod,则会出现以下错误:作为静态方法的Python装饰器,python,decorator,static-methods,Python,Decorator,Static Methods,我正在尝试编写一个python类,它使用需要实例状态信息的decorator函数。这是按预期工作的,但如果我显式地将装饰器设置为staticmetod,则会出现以下错误: Traceback (most recent call last): File "tford.py", line 1, in <module> class TFord(object): File "tford.py", line 14, in TFord @ensure_black Type
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
如果我只是删除了行
@staticmethod
,一切都正常,但我不明白为什么。它不需要将self
作为第一个参数吗?确保\u black
返回的是一个未被@staticmethod
修饰的\u aux
方法
可以将非静态方法返回到静态方法
这不是应该使用的
staticmethod
staticmethod
对象是返回包装对象的对象,因此它们仅在作为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
的范围内,您总是会得到后一个对象,它是不可调用的
我强烈建议将decorator移到模块范围内——它似乎不属于类内部。如果您想将其保留在类内,不要将其设置为
staticmethod
,而只是将其设置在类体的末尾,在这种情况下,它不打算从类外使用。Python类是在运行时在评估类声明的内容后创建的。通过将所有声明的变量和函数赋给一个特殊的字典,并使用该字典调用类型来计算该类
所以
相当于:
A = type.__new__("A", (B,), {"c": 1})
当您用@staticmethod注释一个方法时,在用类型创建类之后会发生一些特殊的魔法。在类声明范围内,@staticmethod函数只是staticmethod对象的一个实例,您不能调用它。decorator可能应该在同一个模块或单独的“decorator”模块中的类定义上方声明(取决于您有多少decorator)。一般来说,装饰符应该在类之外声明。一个值得注意的例外是property类(请参见)。在您的例子中,如果您有类似于颜色类的东西,那么在类声明中包含decorator可能是有意义的:
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'
解决方案确实存在
问题是,试图用作装饰器的静态方法实际上是staticmethod对象,不可调用
解决方案:staticmethod对象具有方法\uuuu get\uuuu
,该方法接受任何参数并返回实际方法: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():
定义初始化(自):
self.n=2
@静力学方法
def_returnBaseAndResult(函数):
从functools导入包装
@包装(func)
def包装(*args,**kwargs):
self=args[0]
响应=func(*args,**kwargs)
返回self.n,响应
返回包装器
@_returnBaseAndResult.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
def方形(自):
返回自我。n**2
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
a=a()
打印(a.square())
将打印(2,4)不,这与此无关。当然有。。如果他正在使用@staticmethod self,则在他的方法上下文中不可用。。(尽管他的代码因此无法工作)为什么您认为需要一个@staticmethod
?很明显,你不明白这意味着什么。静态方法没有绑定到对象的实例,因此它们没有self
参数(也没有访问实例变量的权限)。@Nick:decorator确保\u black
不需要访问self
。它只需要访问func
@Sven:好的观点-我被def get()
也没有使用self
,所以对\u aux
是如何工作的感到困惑。你能看看并发布一下你是如何在没有构造函数的情况下工作的吗?好的,只是要确保_black在这个类之外没有任何用途。我很乐意删除@staticmethod
,我只想知道它为什么会工作。如果没有staticmethod decorator,Survey_black仍然是静态方法吗?@wkz:不,它只是类TFord
范围内定义的普通Python函数。类范围内的函数在任何情况下都不是特殊的。只有通过类似于ford_black.get
的实例访问时,才会对它们进行特殊处理。此表达式不会简单地返回类范围内定义的函数get()
,而是一个“绑定方法包装器”,确保在调用函数时将正确的实例作为self
参数传递——请参见上面的链接和示例。这个例子通过使用A.\uu dict\uuu[“f”]
绕过了特殊处理。马纳克:谢谢!这就是我一直在寻找的答案@SvenMarnach我所做的正是OP所做的,因此您的回答非常有用,谢谢。从技术上讲,staticmethod对象不使用描述符,它们是描述符,假设“如果实现了\uuuu get\uuuu
中的任何一个”的定义。
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'
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