模拟一个';局部静态';python中的变量
考虑以下代码:模拟一个';局部静态';python中的变量,python,Python,考虑以下代码: 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中模拟“局部静态”变量的最简单方法。 困
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.\u 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()
把它变成一个装饰师
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):
...
考虑编写维护缓存的decorator,这样您的函数就不会被缓存代码污染:
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()
。可以创建同样适用于关键字参数的类似decorator,但这次似乎没有必要这样做。将其转换为可调用对象(因为它实际上就是这样的。)
现在,您可以像使用函数一样使用
calcSomething
。但它仍然保持整洁和独立 一个选项是滥用默认参数。即:
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
洛特提出的解决方案也是我提出的解决方案 也有一些有用的“记忆化”装饰器,如:
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
你真的认为这是一种更优雅的方式吗?不,说真的;-)我不认为静态变量是Python中使用的优雅模式,但装饰器至少封装了属性设置的技术细节。+ 1用于Python属性的冷酷使用。保罗-牡蛎:不知道为什么你不认为这个优雅。如果您想要一种非黑客的方式来实现它,只需使用一个带有实例变量的计算器类。你问的是本地静态的,这是天生的丑陋。嗯,作为实用主义者而不是纯粹主义者(加上写C++代码从1991开始……)我不认为本地静态是丑陋的东西。你需要在SytSyVar结尾写代码>返回Obj/<代码>。没有必要弄乱名称(添加下划线),因为它只与static_var.BTW相关,您可能希望用不同的方式表达您的问题。您不是在寻找局部静态变量,而是在寻找一种将记忆引入函数的方法。您的第二个示例比第一个示例更糟糕。您可以返回datetime.datetime.strptime(dts,“%m-%d-%Y%H:%m:%S”),因为strptime是创建新datetime对象的类方法。实际上不需要创建datetime对象。第二个示例是正确的。虽然这不是我问题的目的(见澄清),但这是一个实现本地缓存的漂亮方案。谢谢。如果没有hasattr,你可以摆脱
。。。通过使\u缓存
cacheResults
的局部变量来进行条件设置。+1-另一种隐藏缓存实现的解决方案。我没有想到这种方法,但它看起来比我的简单装饰器更强大。对于那些想使用自定义可调用函数作为方法的人,你必须实现正确的方法(谷歌的“python描述符协议”了解更多)。这种使用专门类加上可调用的组合实际上为不同的情况启用了一种“函数工厂”,由ctor参数控制。+1对于调用,我不知道您可以使用python对象+1:functional+state->functor(即定义了调用的类)。不幸的是,apply已从python 3.0中删除。我也发现了一些类似的例子,它们简短、简单、有用。我认为这不是apply的好用法。更明显的是只调用函数。我想这不会起作用。第一次通过将运行除AttributeError之外的块,将缓存初始化为空dict,然后在calc\u something中的keyerror失败。\u cache[a]=result
@smido我愿意打赌dict.\uuu setitem\uuuuu
抛出内存错误的几率要比抛出keyerror
好得多
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