问题
I\'m trying to write a python class which uses a decorator function that needs information of the instance state. This is working as intended, but if I explicitly make the decorator a staticmetod, I get the following error:
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
Why?
Here is the code:
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()
And if I just remove the line @staticmethod
, everything works, but I do not understand why. Shouldn\'t it need self
as a first argument?
回答1:
This is not how staticmethod
is supposed to be used. staticmethod
objects are descriptors that return the wrapped object, so they only work when accessed as classname.staticmethodname
. Example
class A(object):
@staticmethod
def f():
pass
print A.f
print A.__dict__["f"]
prints
<function f at 0x8af45dc>
<staticmethod object at 0x8aa6a94>
Inside the scope of A
, you would always get the latter object, which is not callable.
I'd strongly recommend to move the decorator to the module scope -- it does not seem to belong inside the class. If you want to keep it inside the class, don't make it a staticmethod
, but rather simply del
it at the end of the class body -- it's not meant to be used from outside the class in this case.
回答2:
Python classes are created at runtime, after evaluating the contents of the class declaration. The class is evaluated by assigned all declared variables and functions to a special dictionary and using that dictionary to call type.__new__
(see customizing class creation).
So,
class A(B):
c = 1
is equivalent to:
A = type.__new__("A", (B,), {"c": 1})
When you annotate a method with @staticmethod, there is some special magic that happens AFTER the class is created with type.__new__
. Inside class declaration scope, the @staticmethod function is just an instance of a staticmethod object, which you can't call. The decorator probably should just be declared above the class definition in the same module OR in a separate "decorate" module (depends on how many decorators you have). In general decorators should be declared outside of a class. One notable exception is the property class (see properties). In your case having the decorator inside a class declaration might make sense if you had something like a color class:
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'
回答3:
ensure_black
is returning a _aux
method that isn't decorated by @staticmethod
You can return a non-static method to a static_method
http://docs.python.org/library/functions.html#staticmethod
来源:https://stackoverflow.com/questions/6412146/python-decorator-as-a-staticmethod