Как это называется и как это можно сделать (`function_name.decorator`)? - PullRequest
3 голосов
/ 15 мая 2011

Очень жаль за очень глупый заголовок, но если бы я знал, что это такое, я бы не писал здесь (:

def some_decorator( func ):
    # ..

class A:
    @some_decorator
    def func():
        pass
    @func.some_decorator    # this one here - func.some_decorator ?
    def func():
        pass

some_decorator украшает func - все в порядке. Но что такое func.some_decorator и как some_decorator становится членом (или чем-то еще?) Из func?

P.S. Я на 90% уверен, что здесь есть такой вопрос (поскольку это кажется чем-то базовым), но я не знаю, как его найти. Если есть дубликат точный , я удалю этот вопрос.


Примечание : не опечатка и не случайность, что обе функции-члены названы func. Декоратор для перегрузки: вопрос связан с Метод декорирования (перегрузка методов класса)

Ответы [ 2 ]

7 голосов
/ 15 мая 2011

Помните, что определение функции с декоратором эквивалентно этому:

def func():
    pass
func = some_decorator(func)

Итак, в следующих строках func относится не к определенной вами функции, а к тому, во что ее превратил декоратор. Также обратите внимание, что декораторы могут возвращать любой объект, а не только функции. Поэтому some_decorator возвращает объект с методом (к сожалению, имена some_decorator и func повторно используются в примере - это сбивает с толку, но ничего не меняет в концепции), который сам по себе является декоратором. Поскольку выражение после @ вычисляется первым, у вас все еще есть ссылка на метод первого декоратора после того, как вы определили другую простую функцию func. Этот декоратор применяется к этой новой функции. Полный пример тогда эквивалентен этому:

class A:
    def func():
        pass
    func = some_decorator(func)

    _decorator = func.some_decorator
    def func():
        pass
    func = _decorator(func)
2 голосов
/ 16 мая 2011

Один из способов прояснить это - продемонстрировать это на конкретном примере, который ведет себя так: дескриптор встроенный property :

class C(object):
    @property
    def x(self):
        "This is a property object, not a function"
        return self._x
    @x.setter
    def x(self, val):
        self._x = val

>>> c = C()
>>> c.x = 1
>>> c.x
1
>>> C.x
<property object at 0x2396100>
>>> C.x.__doc__
'This is a property object, not a function'
>>> C.x.getter.__doc__
'Descriptor to change the getter on a property.'
>>> C.x.setter.__doc__ 
'Descriptor to change the setter on a property.'
>>> C.x.deleter.__doc__
'Descriptor to change the deleter on a property.'

Первый вызов property (в качестве декоратора) означает, что x является , а не функцией - это дескриптор свойства. Особенностью свойств является то, что они позволяют вам изначально определить только метод fget, а затем предоставить fset и fdel позже, используя декораторы property.setter и property.deleter (хотя каждый из них создает новый объект свойства, вам нужно обязательно использовать одно и то же имя каждый раз).

Нечто подобное обычно имеет место, когда вы видите код, использующий этот тип шаблона. В идеале, присвоение имен декораторам позволит достаточно ясно понять, что происходит (например, большинство людей, кажется, понимают идиому для определения property атрибутов достаточно легко).

...