Python: 使用描述符查询缓存发生的方式

Python: Query about the way caching happens using descriptors

我正在尝试使用以下代码使用描述符进行缓存

class TestDesc(object):
    def __init__(self,test):
        self.test = test

    def __get__(self, instance, owner):
        if instance is None:
            return self

        value =  instance.__dict__[self.test.__name__] = self.test(instance)
        return value

    def __set__(self, instance, value):
        pass

class MyClass(object):
    @TestDesc
    def func(self):
        time.sleep(5)
        return "I am very slow"

c = MyClass()
print(c.func)
print(c.func)

两次打印调用都需要 5 秒,这不是它应有的工作方式。但是如果我删除我添加的 __set__ 方法,缓存工作正常。 我无法弄清楚为什么缓存在描述符 class 中的 __set__ 方法无法按预期工作。 任何指针表示赞赏。我正在使用 Python 3.4.1

参考:http://www.pydanny.com/cached-property.html

您发现了 数据描述符 和常规描述符之间的区别。数据描述符在实例属性之前处理,而常规描述符在之后处理。

参见参考文档中的Invoking Descriptors

If the descriptor defines __set__() and/or __delete__(), it is a data descriptor; if it defines neither, it is a non-data descriptor.

[...]

Data descriptors with __set__() and __get__() defined always override a redefinition in an instance dictionary. In contrast, non-data descriptors can be overridden by instances.

强调我的。

并且来自 Descriptor HowTo Guide

If an object defines both __get__() and __set__(), it is considered a data descriptor. Descriptors that only define __get__() are called non-data descriptors (they are typically used for methods but other uses are possible).

Data and non-data descriptors differ in how overrides are calculated with respect to entries in an instance’s dictionary. If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence. If an instance’s dictionary has an entry with the same name as a non-data descriptor, the dictionary entry takes precedence.

您的 TestDecs 描述符有一个 __set__ 方法,因此它被认为是一个数据描述符,并且不查询实例属性以允许始终调用 setter。