2015-02-24 47 views
0

我正在使用來自here的memoize配方,並對返回2值的函數稍作修改。我使用這個包裝來創建兩個單獨的函數,它們分別返回第一個和第二個值,但函數評估被緩存,因此在使用相同參數調用任何返回的函數時沒有開銷。這是這個包裝的代碼。現在記憶類成員函數的包裝以返回部分值

def memoize(obj, cache_limit=10): 
    ''' 
    This function caches the return value each time it is called. partial() is used to return the appropriate value. 
    Cache size is limited to 10 
    See here for details on this design pattern: https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize 
    ''' 
    cache = obj.cache = {} 
    key_cache = collections.deque() 

    @functools.wraps(obj) 
    def memoizer(which, *args, **kwargs): 
     key = str(args) 
     if key not in cache: 
      cache[key] = obj(*args, **kwargs) 
      key_cache.append(key) 
      if len(key_cache) >= cache_limit: 
       del cache[key_cache.popleft()] 
     return cache[key][which] 
    return functools.partial(memoizer, 0), functools.partial(memoizer, 1) 

,我想用這條功能f這是在一個類中定義是這樣的:

class test_function: 
    def __init__(self): 
     '''''' 

    def f(self,x): 
     return 2*x, 3*x 

,我把它叫做這樣

a = test_function() 
f_v1, f_v2 = memoize(a.f) 

如果成功f_v1(x)將返回2xf_v2(x)將返回3x。但是這個錯誤會導致錯誤:

AttributeError: 'instancemethod' object has no attribute 'cache' 

如果函數聲明在類之外,我的代碼就可以正常工作。我錯過了什麼?我正在使用Python 2.7

回答

1

方法是與函數不同類型的對象(對象爲instancemethod,如錯誤消息所示;此類型可用作爲types.MethodType)。與函數對象不同,實例方法沒有__dict__,所以您不能在它們上設置任意屬性;您不能在obj.someMethod.someAttribute = "blah"上創建您自己的自定義屬性,名爲someAttribute

我不清楚爲什麼你要在對象上存儲緩存,因爲你從來沒有真正從那裏訪問它。如果你只需要使用局部變量cache,它將被保存在一個封閉且將正常工作:

def memoize(obj, cache_limit=10): 
    ''' 
    This function caches the return value each time it is called. partial() is used to return the appropriate value. 
    Cache size is limited to 10 
    See here for details on this design pattern: https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize 
    ''' 
    cache = {} 
    key_cache = collections.deque() 

    @functools.wraps(obj) 
    def memoizer(which, *args, **kwargs): 
     key = str(args) 
     if key not in cache: 
      cache[key] = obj(*args, **kwargs) 
      key_cache.append(key) 
      if len(key_cache) >= cache_limit: 
       del cache[key_cache.popleft()] 
     return cache[key][which] 
    return functools.partial(memoizer, 0), functools.partial(memoizer, 1) 

>>> a = test_function() 
... f_v1, f_v2 = memoize(a.f) 
>>> f_v1(2) 
4 
>>> f_v2(2) 
6 
+0

我看看......說我有一個函數'F2()'我想這個包裝到memoize的'cache'不會與'f()'中的'cache'衝突嗎?我檢查了它,它工作正常,但你可以請解釋'緩存'的範圍? – sriramn 2015-02-24 19:47:56

+0

@RazorXsr:由於'cache'是一個局部變量,每次調用'memoize'時都會創建一個新變量。本網站上有關於關閉的各種問題(如[this one](http://stackoverflow.com/questions/4020419/why-arent-python-nested-functions-called-closures))。谷歌的「Python關閉」可以找到很多關於Python關閉的信息。 – BrenBarn 2015-02-24 19:51:02