Декоратор Python как статический метод
Я пытаюсь написать класс 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
в качестве первого аргумента?
Ответы
Ответ 1
Это не означает, что предполагается использовать staticmethod
. staticmethod
объекты дескрипторы, которые возвращают обернутый объект, поэтому они работают только при доступе как 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
вы всегда получите последний объект, который не может быть вызван.
Я настоятельно рекомендую перенести dcorator в область модуля - он, кажется, не входит в класс. Если вы хотите сохранить его внутри класса, не делайте его staticmethod
, а просто del
в конце тела класса - он не должен использоваться извне класса в этом случае.
Ответ 2
Классы Python создаются во время выполнения, после оценки содержимого объявления класса. Класс оценивается путем назначения всех объявленных переменных и функций специальному словарю и использования этого словаря для вызова type.__new__
(см. настройка создания класса).
Итак,
class A(B):
c = 1
эквивалентно:
A = type.__new__("A", (B,), {"c": 1})
Когда вы комментируете метод с помощью метода @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'
Ответ 3
ensure_black
возвращает метод _aux
, который не украшен @staticmethod
Вы можете вернуть нестатический метод в static_method
http://docs.python.org/library/functions.html#staticmethod