请考虑以下代码:
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()
S.Lott.. 52
把它变成一个可调用的对象(因为它实际上就是这样.)
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
像使用它一样使用它.但它仍然是整洁和自足的.
把它变成一个可调用的对象(因为它实际上就是这样.)
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
像使用它一样使用它.但它仍然是整洁和自足的.
把它变成装饰者.
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): ...
考虑编写将保持缓存的装饰器,您的功能不会被缓存代码污染:
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()
在任何你不需要关键字参数的地方使用.可以创建类似的装饰器,也适用于关键字参数,但这次似乎没有必要.