这个Python装饰器是如何工作的?

时间:2010-06-23 16:16:48

标签: python decorator

我正在查看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 个答案:

答案 0 :(得分:8)

在类someprop的实例o上访问名为SomeClass的属性时,如果SomeClass包含名为{{1}的描述符然后使用该描述符的类o方法。有关描述符的更多信息,请参阅this guide。不要让__get__在语法上作为装饰器使用这一事实,使你的实例成为描述符,因为Lazy本身有一个Lazy方法。 / p>

装饰器语法

__get__

不仅仅是语法糖,而且不亚于:

    @Lazy
    def someprop(self):
       ...

def someprop(self): ... someprop = Lazy(someprop) 的约束与装饰器语法或直接使用时没有区别:它必须接受Lazy(一个函数)作为其参数 - 对它返回的内容没有任何限制。这里,someprop是一个类,所以它返回一个自身的实例,并且有一个Lazy特殊方法,因此实例是一个描述符(所以当访问__get__属性时调用所述方法在类someprop的实例o上 - 这就是它的全部内容,不多也不少。