我在Python中装饰静态方法时遇到了一些问题。我认为以下代码最能代表我的问题:
def decorator(func):
print callable(func)
return func
class Foo():
@decorator
@staticmethod
def bar():
return
# outputs False
print callable(Foo.bar)
# outputs True
这似乎是一个错误。我想它会出现,因为当方法Foo.bar
被传递给装饰器时,它是一个函数,而不是一个方法。这是我可以看到它不可调用的唯一原因,因为如果我们装饰一个标准函数,它就不可调用,如下所示。
@staticmethod
def function():
return
print callable(function)
# outputs False
这是静态方法装饰器实现中的一个真正的错误,和/或是否有任何简单的解决方法?我确实想过写一个装饰器来指定一个__call__
属性,但我不知道callable
是如何实现的,所以我无法衡量这种方法的成功。
答案 0 :(得分:6)
方法是函数。但staticmethod
对象不是。它们是descriptors,所以当你以Cls.static_method
的形式访问它时,会有额外的魔法给你一个可调用的,但是这个魔法在你使用时无法隐藏任何东西(即传递给装饰者)static_method
在Cls
的身体内。你不能真正破解你的方式,至少不干净。一个更简单的解决方案是重新排序装饰器,使得最后应用staticmethod
- 即将它放在顶部,高于所有其他装饰器。
答案 1 :(得分:4)
好吧,无论你是否认为它是一个错误,它都是documented:
静态方法对象提供了一种破坏转换的方法 函数对象到方法对象 如上所述。静态方法 object是任何其他的包装器 对象,通常是用户定义的方法 宾语。当一个静态方法对象是 从类或类中检索 实例,实际返回的对象 是包装的对象,不是 受任何进一步的转变。 静态方法对象不是 他们自己可以打电话,虽然 他们通常包裹的物品。静态的 方法对象由。创建 内置的staticmethod()构造函数。
答案 2 :(得分:1)
我编写了自己的staticmethod
实现, 可以调用,这似乎很好地解决了这个问题。
class staticmethod(object):
"""Make @staticmethods play nice with @memoize."""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
"""Call the static method with no instance."""
return self.func(*args, **kwargs)
这不使用描述符协议,因此内部行为与内置staticmethod
的行为非常不同,但实际上它使函数可以作为类属性,实例属性,甚至作为函数属性调用(即,如果你已经在一个装饰函数中包装了你的类,staticmethod的这个实现仍然允许你将静态方法作为包装函数的属性来调用。)