python 在python中模拟“局部静态”变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/460586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:10:26  来源:igfitidea点击:

Simulating a 'local static' variable in python

python

提问by Paul Oyster

Consider the following code:

考虑以下代码:

def CalcSomething(a):
    if CalcSomething._cache.has_key(a):
      return CalcSomething._cache[a]
    CalcSomething._cache[a] = ReallyCalc(a)
    return CalcSomething._cache[a] 

CalcSomething._cache = { }

This is the easiest way I can think of for simulating a 'local static' variable in python.
What bothers me is that CalcSomething._cache is mentioned outside the function's definition, but the alternative would be something like that:

这是我能想到的在 python 中模拟“局部静态”变量的最简单方法。
困扰我的是 CalcSomething._cache 在函数的定义之外被提及,但替代方案是这样的:

if not hasattr(CalcSomething, "_cache"):  
    setattr(CalcSomething, "_cache", { } )  

inside the function's definition, which is really cumbersome.

在函数的定义里面,真的很麻烦。

Is there a more elegant way?

有没有更优雅的方式?

[EDIT]
Just to clarify, this question is not about local function caches, as the example above might suggest. Here is another short example where a 'static local' might be handy:

[编辑]
只是为了澄清,这个问题与本地函数缓存无关,如上面的示例所示。这是另一个简短的示例,其中“静态本地”可能很方便:

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() 

回答by S.Lott

Turn it into a callable object (since that's what it really is.)

把它变成一个可调用的对象(因为它确实是这样。)

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()

Now you can use calcSomethingas if it were a function. But it remains tidy and self-contained.

现在您可以calcSomething像使用函数一样使用它。但它仍然保持整洁和独立。

回答by Torsten Marek

Turn it into a decorator.

把它变成一个装饰器。

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):
    ...

回答by Abgan

Consider writing decorator that will maintain cache and your function won't be contaminated by caching code:

考虑编写将维护缓存并且您的函数不会被缓存代码污染的装饰器:

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)

Maybe it doesn't look great at first, but you can use cacheResults()anywhere you don't need keyword parameters. It is possible to create similar decorator that would work also for keyword params, but that didn't seem necessary this time.

也许一开始看起来不太好,但是您可以cacheResults()在不需要关键字参数的任何地方使用。可以创建类似的装饰器,这些装饰器也适用于关键字参数,但这一次似乎没有必要。

回答by tzot

The solution proposed by S.Lott is the solution I would propose too.

S.Lott 提出的解决方案也是我提出的解决方案。

There are useful "memoize" decorators around, too, like:

周围也有有用的“记忆”装饰器,例如:

Given all that, I'm providing an alternative for your initial attempt at a function and a "static local", which is standalone:

鉴于所有这些,我为您对函数和独立的“静态本地”的初始尝试提供了替代方案:

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

回答by Brian

One option is to abuse default parameters. ie:

一种选择是滥用默认参数。IE:

def CalcSomething(a, _cache={}):
    if _cache.has_key(a):

This has the advantage that you don't need to qualify the name, and will get fast local access to the variables rather than doing two slow dict lookups. However it still has the problem that it is mentioned outside the function (in fact it's worse since its now in the function signature.)

这样做的好处是您不需要限定名称,并且可以快速本地访问变量,而不是进行两次缓慢的 dict 查找。然而,它仍然存在在函数之外被提及的问题(实际上,它现在在函数签名中更糟。)

To prevent this, a better solution would be to wrap the function in a closure containing your statics:

为了防止这种情况,更好的解决方案是将函数包装在包含静态的闭包中:

@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