请考虑以下代码:
def CalcSomething(a):
if CalcSomething._cache.has_key(a):
return CalcSomething._cache[a]
CalcSomething._cache[a] = ReallyCalc(a)
return CalcSomething._cache[a]
CalcSomething._cache = { }
这是我在python中模拟“局部静态”变量时最容易想到的方法 困扰我的是在函数的定义之外提到了CalcSomething._cache,但替代方案就是这样:
if not hasattr(CalcSomething, "_cache"):
setattr(CalcSomething, "_cache", { } )
在函数的定义中,这真的很麻烦。
有更优雅的方式吗?
[编辑]
只是为了澄清,这个问题不是关于本地函数缓存,正如上面的例子所暗示的那样。这是另一个简短的例子,其中'静态本地'可能很方便:
def ParseString(s):
return ParseString._parser.parse(s)
# Create a Parser object once, which will be used for all parsings.
# Assuming a Parser object is heave on resources, for the sake of this example.
ParseString._parser = Parser()
答案 0 :(得分:50)
将它变成一个可调用的对象(因为它实际上就是这样。)
class CalcSomething(object):
def __init__(self):
self._cache = {}
def __call__(self, a):
if a not in self._cache:
self._cache[a] = self.reallyCalc(a)
return self._cache[a]
def reallyCalc(self, a):
return # a real answer
calcSomething = CalcSomething()
现在您可以使用calcSomething
,就像它是一个函数一样。但它仍然是整洁和自足的。
答案 1 :(得分:17)
把它变成装饰者。
def static_var(var_name, initial_value):
def _set_var(obj):
setattr(obj, var_name, initial_value)
return obj
return _set_var
@static_var("_cache", {})
def CalcSomething(a):
...
答案 2 :(得分:11)
考虑编写将保持缓存的装饰器,并且您的功能不会被缓存代码污染:
def cacheResults(aFunc):
'''This decorator funcion binds a map between the tuple of arguments
and results computed by aFunc for those arguments'''
def cachedFunc(*args):
if not hasattr(aFunc, '_cache'):
aFunc._cache = {}
if args in aFunc._cache:
return aFunc._cache[args]
newVal = aFunc(*args)
aFunc._cache[args] = newVal
return newVal
return cachedFunc
@cacheResults
def ReallyCalc(a):
'''This function does only actual computation'''
return pow(a, 42)
一开始可能看起来不太好,但您可以在不需要关键字参数的任何地方使用cacheResults()
。可以创建类似的装饰器,也适用于关键字参数,但这次似乎没有必要。
答案 3 :(得分:4)
S.Lott提出的解决方案也是我建议的解决方案。
周围也有一些有用的“memoize”装饰器,如:
考虑到所有这些,我提供了一个替代你的初始尝试功能和一个“静态本地”,这是独立的:
def calc_something(a):
try:
return calc_something._cache[a]
except AttributeError: # _cache is not there
calc_something._cache= {}
except KeyError: # the result is not there
pass
# compute result here
calc_something._cache[a]= result
return result
答案 4 :(得分:3)
一种选择是滥用默认参数。即:
def CalcSomething(a, _cache={}):
if _cache.has_key(a):
这样做的好处是您不需要限定名称,并且可以快速本地访问变量,而不是进行两次慢速dict查找。然而,它仍然存在在函数外部提到它的问题(实际上它现在在函数签名中更糟糕。)
为了防止这种情况,更好的解决方案是将函数包装在包含静态的闭包中:
@apply
def CalcSomething():
cache = {} # statics go here
def CalcSomething(a):
if cache.has_key(a):
return cache[a]
cache[a] = ReallyCalc(a)
return cache[a]
return CalcSomething