2015-02-24 46 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