我正在查看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)()
它会引发异常正如所料。我错过了什么?
答案 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
上 - 这就是它的全部内容,不多也不少。