2015-02-11 45 views
0

使用的描述,我嘗試使用緩存下面的代碼的Python:查詢有關辦法緩存使用情況的描述

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__方法,緩存工作正常。 我無法弄清楚爲什麼緩存不能按預期的方式在描述符類中使用__set__方法。 任何指針讚賞。我使用Python 3.4.1

編號:http://www.pydanny.com/cached-property.html

回答

1

你想出了一條數據描述符和常規描述符之間的差異。數據描述符在實例屬性之前處理,而常規描述符在之後處理。

參見Invoking Descriptors在參考documenation:

如果描述符定義__set__()和/或__delete__(),它是一種數據描述符;如果它既不定義,它也是一個非數據描述符。

[...]

__set__()和定義始終覆蓋在一個實例字典重新定義__get__()數據描述符。相反,非數據描述符可以被實例覆蓋。

強調我的。

而且從Descriptor HowTo Guide

如果一個對象定義了__get__()__set__(),它被認爲是一個數據描述符。只定義爲__get__()的描述符被稱爲非數據描述符(它們通常用於方法,但其他用途也是可能的)。

數據和非數據描述符在如何計算實例字典中的條目的覆蓋方面有所不同。 如果實例的字典中有一個與數據描述符名稱相同的條目,則數據描述符的優先級爲。如果實例的字典中有一個與非數據描述符名稱相同的條目,則字典條目優先。

TestDecs描述有__set__方法,因此它被認爲是一個數據描述符和實例屬性不協商,以允許總是調用的二傳手。

+0

我猜測代碼的核心是在「value = instance .__ dict __ [self.test .__ name__] = self.test(instance)」中。所以你的意思是如果我定義__set__,它的作用就像「value = self.test(instance)」,否則就是「value = instance .__ dict __ [self.test .__ name__]」? – 2015-02-11 19:33:02

+1

@RohitSasikumar:該行在該實例上設置屬性與屬性完全相同的名稱;對於非數據描述符,然後覆蓋該名稱的所有將來訪問。如果你有一個'__set__'方法,使它成爲一個數據描述符,'__get__'方法總是會被調用,所以在你的getter中你需要檢查你是否已經設置了一個緩存值並返回值,而不是調用該方法。 – 2015-02-11 20:17:11

相關問題