2017-04-24 134 views
3

目標是創建一個自定義python類,它允許對屬性進行延遲加載(這裏有一個相當常見的問題,這裏有各種不同的解決方案),但是一次只運行昂貴的初始化步驟懶惰的訪問。這裏有一個例子:對第一類屬性訪問的Python自定義初始化

class LazyDateModule() 
    def __init__(self, args): 
     self.args = args 
     self._expensive_date_attr = None 

    def _expensive_init(): 
     time.sleep(10) 
     self._expensive_date_attr = date.today() 

    @memoize 
    def date_str(): 
     return str(self._expensive_date_attr) 

    @memoize 
    def month_num(): 
     return self._expensive_date_attr.month 

在這個例子中,我@memoize裝飾處理我的緩存一步。

如果我在其他地方定義我LazyDateModule:

LDM = LazyDateModule() 

如何只在第一次任memoized屬性方法進行訪問運行_expensive_init()?我試過這樣的事情:

class LazyDateModule() 
    def __init__(self, args): 
     self.args = args 
     self._assembled = False 
     self._expensive_date_attr = None 

    def _expensive_init(): 
     time.sleep(10) 
     self._expensive_date_attr = date.today() 
     self._assembled = True 

    @memoize 
    def date_str(): 
     if self._assembled is False: 
      self._expensive_init() 
     return str(self._expensive_date_attr) 

    @memoize 
    def month_num(): 
     if self._assembled is False: 
      self._expensive_init() 
     return self._expensive_date_attr.month 

但這不是很乾淨。理想情況下,我希望這種行爲要麼在班級級別上 - 但是我試圖覆蓋__getattr____getattribute__。另一個裝飾者也會工作。

如果上述內容令人困惑,我很抱歉。讓我知道,如果我能以任何方式澄清它!編輯1: 我認爲上面的例子有點太簡單了。假設我的_expensive_init()做了一堆東西,而不是隻定義一個屬性。

def _expensive_init(self): 
    time.sleep(5) 
    self._expensive_date_attr = date.today() 

    time.sleep(1) 
    # send a message to someone saying that this occurred 

    time.sleep(1) 
    # run a db call to update when this action occurred 

    etc... 

理想情況下,此方法將處理各種不同的行爲。

+0

我寫了一個類似的模塊。我決定不完成它。它分兩步工作。在第一步中,一個簡單的方法裝飾器通過向裝飾函數本身添加一個屬性來註冊每個要記憶的方法。這個階級本身並不存在,所以這就是它所能做到的。在第二步中,類裝飾器檢查所添加屬性的所有方法,創建表,從類中移除這些方法,並安裝一個自定義的__getattr__來捕獲對錶中名稱的第一次訪問,調用該函數並添加結果作爲常規屬性。希望能幫助到你。 – VPfB

回答

2

你有一個緩存修飾器memoize,那麼爲什麼不用它來緩存你的_expensive_date_attr?和BTW把它變成一個屬性:

class LazyDateModule(): 
    def __init__(self, args): 
     self.args = args 
     self._assembled = False 

    @memoize 
    @property 
    def _expensive_date_attr(self): 
     return date.today 

    @memoize 
    def date_str(): 
     return str(self._expensive_date_attr) 

    @memoize 
    def month_num(): 
     return self._expensive_date_attr.month 
+0

爲什麼'date_str'和'month_num'應該被記憶呢? – VPfB

+0

沒有其他原因,他們被記憶在你的代碼 – Guillaume

+0

這是乾淨的,但不幸的是,我不認爲這將適用於我所設想的。這方面的例子太簡單了。查看我最近的更改。 – dizzyf