Подтвердить что ты не робот

Декоратор 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 в качестве первого аргумента?

4b9b3361

Ответ 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'