作为静态方法的Python装饰器

作为静态方法的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

我正在尝试编写一个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
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