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

3

我正在研究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
当在类SomeClass的实例o上访问名为someprop的属性时,如果SomeClass包含名为o描述符,则该描述符的类的__get__方法将被使用。有关描述符的更多信息,请参见this guide。不要因为Lazy在语法上被用作装饰器而忽略其实例是描述符的事实,因为Lazy本身具有__get__方法。

装饰器语法

    @Lazy
    def someprop(self):
       ...

不多不少,只是语法糖的写法:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接