Python: Decorated staticmethod receives non
I'm having a little problem decorating a static method in Python. I think the following code best represents my problem:
def decorator(func):
print callable(func)
return func
class Foo():
@decorator
@staticmethod
def bar():
return
# outputs False
print callable(Foo.bar)
# outputs True
This seems to be a bug. I imagine it arises because when the method Foo.bar
is passed to the decorator, it is a function, not a method. That is the only reason I can see for it not being callable, for if we decorate a standard function, it is not callable, as shown below.
@staticmethod
def function():
return
print callable(function)
# outputs False
So is this a true bug in implementation of the staticmethod decorator, and/or are there any simple workarounds? I did think of writing a decorator to asign a __call__
attribute, but I don't know how callable
is implemented, so I can't gauge the sucess of such a method.
Methods are functions. But staticmethod
objects aren't. They are descriptors, so there's extra magic that gives you a callable when you access it as Cls.static_method
, but this magic can't hide anything when you use (ie pass to decorator) static_method
inside the body of Cls
. You can't really hack your way around this, at least not cleanly. A much simpler solution is reordering the decorators such that staticmethod
get applied last - ie put it at the top, above all other decorators.
Well, whether you consider it a bug or not, it's documented:
Static method objects provide a way of defeating the transformation of function objects to method objects described above. A static method object is a wrapper around any other object, usually a user-defined method object. When a static method object is retrieved from a class or a class instance, the object actually returned is the wrapped object, which is not subject to any further transformation. Static method objects are not themselves callable, although the objects they wrap usually are. Static method objects are created by the built-in staticmethod() constructor.
I wrote my own implementation of staticmethod
that is callable and this seems to solve this problem nicely.
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)
This doesn't use the descriptor protocol and as such behaves very differently than the builtin staticmethod
internally, however in practice it makes functions callable as class attributes, instance attributes, and even as function attributes (ie, if you've wrapped your class in a decorating function, this implementation of staticmethod will still allow you to call your static methods as attributes on the wrapping function).
上一篇: 风格和新
下一篇: Python:装饰的静态方法接收非