Python装饰器作为静态方法

wkz*_*wkz 43 python static-methods decorator

我正在尝试编写一个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
Run Code Online (Sandbox Code Playgroud)

为什么?

这是代码:

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()
Run Code Online (Sandbox Code Playgroud)

如果我只是删除线@staticmethod,一切正常,但我不明白为什么.它不应该self作为第一个论点吗?

Sve*_*ach 43

这不staticmethod应该如何使用. staticmethod对象是返回包装对象的描述符,因此它们仅在访问时才起作用classname.staticmethodname.例

class A(object):
    @staticmethod
    def f():
        pass
print A.f
print A.__dict__["f"]
Run Code Online (Sandbox Code Playgroud)

版画

<function f at 0x8af45dc>
<staticmethod object at 0x8aa6a94>
Run Code Online (Sandbox Code Playgroud)

A你的范围内,你总是得到后一个不可调用的对象.

我强烈建议将装饰器移动到模块范围 - 它似乎不属于类.如果你想把它保留在类中,不要把它变成一个staticmethod,而是简单地del把它放在类体的末尾 - 在这种情况下,它并不意味着在类之外使用它.

  • @wkz:不,它只是在`TFord`类范围内定义的普通Python函数.无论如何,类范围内的函数都不是特殊的.只有在`ford_black.get`中的实例访问它们时才会对它们进行特殊处理.这个表达式不会简单地返回类范围内定义的函数`get()`,而是返回一个"绑定方法包装器",它确保在调用函数时将正确的实例作为`self`参数传递 - 请参阅以上链接和示例.这个例子通过使用`A .__ dict __ ["f"]`来规避特殊处理. (3认同)

jfo*_*cht 7

在评估类声明的内容之后,在运行时创建Python类.通过将所有声明的变量和函数分配给特殊字典并使用该字典调用来评估该类type.__new__(请参阅自定义类创建).

所以,

class A(B):
    c = 1
Run Code Online (Sandbox Code Playgroud)

相当于:

A = type.__new__("A", (B,), {"c": 1})
Run Code Online (Sandbox Code Playgroud)

当您使用@staticmethod注释方法时,在创建类之后会发生一些特殊的魔法type.__new__.在类声明范围内,@ staticmethod函数只是staticmethod对象的一个​​实例,您无法调用它.装饰器可能只应在同一模块中的类定义之上或单独的"装饰"模块中声明(取决于你有多少个装饰器).通常,装饰器应该在类之外声明.一个值得注意的例外是属性类(请参阅属性).在你的情况下,如果你有类似颜色类的东西,那么装饰器在类声明中可能是有意义的:

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'
Run Code Online (Sandbox Code Playgroud)