Python装饰器作为静态方法

时间:2011-06-20 13:43:35

标签: python decorator static-methods

我正在尝试编写一个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作为第一个参数吗?

4 个答案:

答案 0 :(得分:41)

这不是staticmethod的使用方式。 staticmethoddescriptors对象返回包装对象,因此只有在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在课堂体的末尾 - 它不是要在课外使用在这种情况下。

答案 1 :(得分:7)

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

所以,

class A(B):
    c = 1

相当于:

A = type.__new__("A", (B,), {"c": 1})

当您使用@staticmethod注释方法时,在使用type.__new__创建类之后会发生一些特殊的魔法。在类声明范围内,@ staticmethod函数只是staticmethod对象的一个​​实例,您无法调用它。装饰器可能只应在同一模块中的类定义之上或单独的“装饰”模块中声明(取决于你有多少个装饰器)。通常,装饰器应该在类之外声明。一个值得注意的例外是属性类(请参阅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'

答案 2 :(得分:0)

今天,我希望仅在类内部使用静态方法装饰器。

问题是试图用作装饰器的静态方法实际上是staticmethod对象,并且不可调用。

解决方案:静态方法对象具有方法__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)

答案 3 :(得分:-1)

ensure_black返回的_aux方法未被@staticmethod

修饰

您可以将非静态方法返回到static_method

http://docs.python.org/library/functions.html#staticmethod