简体   繁体   English

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

[英]How does this Python decorator work?

I was looking at some lazy loading property decorators in Python and happened across this example ( http://code.activestate.com/recipes/363602-lazy-property-evaluation/ ): 我在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

My question is, how does this work? 我的问题是,这是如何工作的? My understanding of decorators is that they must be callable (so either a function or a call that implements __call__ ), but Lazy here clearly is not and if I try Lazy(someFunc)() it raises an exception as expected. 我对装饰器的理解是它们必须是可调用的(所以函数或实现__call__ ),但是Lazy在这里显然不是,如果我尝试Lazy(someFunc)()它会按预期引发异常。 What am I missing? 我错过了什么?

When an attribute named someprop is accessed on instance o of class SomeClass , if SomeClass contains a descriptor named o , then that descriptor's class's __get__ method is used. 当在类SomeClass实例o上访问名为someprop的属性时,如果SomeClass包含名为o描述符 ,则使用该描述符的类的__get__方法。 For more on descriptors, see this guide . 有关描述符的更多信息,请参阅本指南 Don't let the fact that Lazy is here used, syntactically, as a decorator, blind you to the fact that its instances are descriptors, because Lazy itself has a __get__ method. 不要让Lazy在语法上作为装饰器使用这个事实,因为它的实例是描述符,因此Lazy你,因为Lazy本身有一个__get__方法。

The decorator syntax 装饰器语法

    @Lazy
    def someprop(self):
       ...

is no more, and no less, than syntax sugar for: 不仅仅是语法糖,而且不亚于:

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

The constraints on Lazy are no different when it's used with decorator syntax or directly: it must accept someprop (a function) as its argument -- no constraints whatsoever on what it returns. 当它与装饰器语法或直接一起使用时,对Lazy的约束没有什么不同:它必须接受someprop (一个函数)作为它的参数 - 对它返回的内容没有任何约束。 Here, Lazy is a class so it returns an instance of itself, and has a __get__ special method so that instance is a descriptor (so said method gets called when the someprop attribute is accessed on the instance o of class SomeClass ) -- that's all there is to it, no more, and no less. 这里, Lazy是一个类,所以它返回一个自身的实例,并且有一个__get__特殊方法,因此实例是一个描述符(所以当在SomeClass类的实例o上访问someprop属性时调用所述方法) - 这就是全部有它,不多也不少。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM