2017-03-03 62 views
3

我有以下的僞代碼:記憶化裝飾

class myClass() 
    def slow_method(self): 
    try: 
     return self.memo_slow_method 
    except: 
     self.memo_slow_method = some_slow_function() 
     return self.memo_slow_method 

是否有可能建立一個執行這個邏輯正好一個memoization的設計師嗎?

限制:

  • 雖然memo_slow_method並不需要直接訪問,就必須在對象上進行定義,使得它清理時對象本身是驅除氣體非常重要
  • 沒有必要考慮除self以外的參數 - 不會傳遞任何參數。

PS我一直在使用@lrucache,但它不適合我的目的。它確實需要嚴格遵循上述邏輯。

+0

會有什麼some_slow_function回來嗎?方法還是值?請問slow_method函數返回嗎? –

+0

有一個[memoization修飾器的配方](https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize)。由於Python 3.2,[類似](https://docs.python.org/3/library/functools.html#functools.lru_cache)包含在標準庫中。 – mkrieger1

回答

2

相反,你可以使用一個描述符(財產等),一個裝飾的:

class Memoize(object): 
    def __init__(self, name, func): 
     self.name = name # name of the memo attribute 
     self.func = func # the function that is executed when there is no memo 

    def __get__(self, obj, typ=None): 
     if obj: 
      try: 
       return getattr(obj, self.name) 
      except: 
       setattr(obj, self.name, self.func()) 
       return getattr(obj, self.name) 
     else: 
      return self 

然後設置描述:

class Fun(object): 
    meth = Memoize('x', lambda: print('in') or 10) 

然後交互式測試:

>>> f = Fun() 
>>> f.meth # function is executed 
'in' 
10 
>>> f.x 
10 
>>> f.meth # function is not executed 
10 

如果你真的想要一個裝飾者:

def memoize(func): 
    def inner(self): 
     try: 
      return self.memo_slow_method # hardcoded memo attribute name 
     except: 
      self.memo_slow_method = func(self) # execute the method body 
      return self.memo_slow_method 
    return inner 

class Fun(object): 
    @memoize 
    def meth(self): 
     print('in') 
     return 100 

>>> f = Fun() 
>>> f.meth() 
'in' 
100 
>>> f.meth() 
100 
>>> f.memo_slow_method 
100 
0

這是一個裝飾器,可按要求準確地實現您的邏輯。 它硬幣從函數名(這是提供func.__name__)備註字段的名稱添加前綴到它:

from __future__ import print_function 
import time 
from functools import wraps 

memo_prefix = '_memo_' # Check for possible name collision 

def deco(func): 
    memo_field_name = memo_prefix + func.__name__ 

    def ret_func(self): 
     try: 
      return getattr(self, memo_field_name) 
     except AttributeError: 
      ret_val = func(self) 
      setattr(self, memo_field_name, ret_val) 
      return ret_val 
    return ret_func 

def some_slow_function(): 
    for x in range(3): 
     time.sleep(1) 
     print('Waiting...', x) 
    return 'Done' 

class myClass(): 
    @deco 
    def slow_method(self): 
     return some_slow_function() 

現在測試一下:

In [2]: it = myClass() 

In [3]: print(it.slow_method()) 
Waiting... 0 
Waiting... 1 
Waiting... 2 
Done 

In [4]: print(it.slow_method()) 
Done 

In [5]: print(it.__dict__) 
{'_memo_slow_method': 'Done'}