Python 类成员函数的Memoize包装器以返回部分值
我使用的是来自的memoize配方,并对其进行了轻微修改,使其用于返回2个值的函数。我使用这个包装器创建两个单独的函数,分别返回第一个值和第二个值,但是函数求值是缓存的,这样当使用相同的参数调用任何一个返回的函数时就不会有开销。下面是这个包装器的代码Python 类成员函数的Memoize包装器以返回部分值,python,wrapper,memoization,functools,Python,Wrapper,Memoization,Functools,我使用的是来自的memoize配方,并对其进行了轻微修改,使其用于返回2个值的函数。我使用这个包装器创建两个单独的函数,分别返回第一个值和第二个值,但是函数求值是缓存的,这样当使用相同的参数调用任何一个返回的函数时就不会有开销。下面是这个包装器的代码 def memoize(obj, cache_limit=10): ''' This function caches the return value each time it is called. partial() is use
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)
将返回2x
,f_v2(x)
将返回3x
。但这失败了,出现了一个错误:
AttributeError: 'instancemethod' object has no attribute 'cache'
如果函数在类之外声明,我的代码可以正常工作。我错过了什么?我使用的是
Python2.7
方法是一种与函数不同的对象(如错误消息所示,是一种instancemethod
对象;这种类型可用作types.MethodType
)。与函数对象不同,实例方法没有\uuuu dict\uuu
,因此不能对其设置任意属性;您不能通过obj.someMethod.someAttribute=“blah”
在方法上创建自己的名为someAttribute
的自定义属性
我不清楚为什么要将缓存存储在对象上,因为实际上从未从那里访问它。如果只使用局部变量缓存
,它将保存在闭包中,并且可以正常工作:
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
我懂了。。。假设我有一个函数
f2()
,我想用这个包装器来记忆它,缓存
会不会与f()
中的缓存
冲突?我检查了它,它工作正常,但是您能解释一下缓存的范围吗?@RazorXsr:由于缓存
是一个局部变量,因此每次调用memoize
时都会创建一个新的变量。这个网站上有很多关于闭包的问题(比如)。谷歌搜索“Python闭包”可以找到很多关于Python闭包的信息。