Как работает этот Python decorator? - PullRequest
3 голосов
/ 23 июня 2010

Я смотрел на некоторые ленивые загрузчики декораторов свойств в Python и натолкнулся на этот пример (http://code.activestate.com/recipes/363602-lazy-property-evaluation/):

class Lazy(object):
    def __init__(self, calculate_function):
        self._calculate = calculate_function

    def __get__(self, obj, _=None):
        if obj is None:
            return self
        value = self._calculate(obj)
        setattr(obj, self._calculate.func_name, value)
        return value

# Sample use:

class SomeClass(object):

    @Lazy
    def someprop(self):
        print 'Actually calculating value'
        return 13

o = SomeClass()
o.someprop
o.someprop

Мой вопрос: как это работает? Я понимаю, что декораторы должны бытьвызываемый (так что это либо функция, либо вызов, который реализует __call__), но Lazy здесь явно нет, и если я пытаюсь Lazy(someFunc)(), это вызывает исключение, как и ожидалось. Чего мне не хватает?

1 Ответ

8 голосов
/ 23 июня 2010

Когда атрибут с именем someprop доступен в экземпляре o класса SomeClass, если SomeClass содержит дескриптор с именем o, то метод __get__ класса этого дескриптора используемый. Подробнее о дескрипторах см. в этом руководстве . Не позволяйте тому факту, что Lazy здесь используется синтаксически в качестве декоратора, вы не ослепляете вас тем фактом, что его экземпляры являются дескрипторами, потому что сам Lazy имеет метод __get__.

Синтаксис декоратора

    @Lazy
    def someprop(self):
       ...

не больше и не меньше, чем синтаксический сахар для:

    def someprop(self):
       ...
    someprop = Lazy(someprop)

Ограничения на Lazy ничем не отличаются, когда он используется с синтаксисом декоратора или напрямую: он должен принимать someprop (функцию) в качестве аргумента - никаких ограничений на то, что он возвращает. Здесь Lazy является классом, поэтому он возвращает сам экземпляр и имеет специальный метод __get__, чтобы экземпляр был дескриптором (поэтому указанный метод вызывается при обращении к атрибуту someprop в экземпляре o класса SomeClass) - это все, что нужно, не больше и не меньше.

...