Python中的静态变量?

问题描述 投票:11回答:5

在C ++中我们有静态关键字,在循环中是这样的:

for(int x=0; x<10; x++)
    {
      for(int y=0; y<10; y++)
      {
        static int number_of_times = 0;
        number_of_times++;
      }
    }

静态在这里使number_of_times初始化一次。我怎么能在python 3.x中做同样的事情?

编辑:由于大多数人感到困惑,我想指出我给出的代码只是C ++静态用法的一个例子。我真正的问题是我想在函数中只初始化一个时间变量,因为我不希望它是全局的(等等!)或默认参数..

python python-3.x
5个回答
21
投票

假设你想要的是“一个在第一次函数调用时只初始化一次的变量”,那么在Python语法中就没有这样的东西了。但有一些方法可以获得类似的结果:

1 - 使用全局。请注意,在Python中,“全局”实际上意味着“模块的全局”,而不是“流程的全局”:

_number_of_times = 0

def yourfunc(x, y):
    global _number_of_times
    for i in range(x):
        for j in range(y):
            _number_of_times += 1

2 - 将代码包装在类中并使用类属性(即:所有实例共享的属性)。 :

class Foo(object):
    _number_of_times = 0

    @classmethod
    def yourfunc(cls, x, y):
        for i in range(x):
            for j in range(y):
                cls._number_of_times += 1

请注意,我使用了classmethod,因为此代码段不需要实例中的任何内容

3 - 将代码包装在类中,使用实例属性并为方法提供快捷方式:

class Foo(object):
    def __init__(self):
         self._number_of_times = 0

    def yourfunc(self, x, y):
        for i in range(x):
            for j in range(y):
                self._number_of_times += 1

yourfunc = Foo().yourfunc

4 - 编写可调用类并提供快捷方式:

class Foo(object):
    def __init__(self):
         self._number_of_times = 0

    def __call__(self, x, y):
        for i in range(x):
            for j in range(y):
                self._number_of_times += 1


yourfunc = Foo()

4 bis - 使用class属性和元类

class Callable(type):
    def __call__(self, *args, **kw):
        return self._call(*args, **kw)

class yourfunc(object):
    __metaclass__ = Callable

    _numer_of_times = 0

    @classmethod
    def _call(cls, x, y):
        for i in range(x):
            for j in range(y):                 
                cls._number_of_time += 1

5 - 对模块导入时仅实例化一次的函数默认参数进行“创造性”使用:

def yourfunc(x, y, _hack=[0]):
    for i in range(x):
        for j in range(y):
            _hack[0] += 1

还有一些其他可能的解决方案/黑客攻击,但我认为你现在可以了解大局。

编辑:给出操作的澄清,即“让我们说你有一个带有默认参数的递归函数,但是如果有人真的试图给你的函数多一个参数它可能是灾难性的”,它看起来像OP真正想要的是:

# private recursive function using a default param the caller shouldn't set
def _walk(tree, callback, level=0):
    callback(tree, level)
    for child in tree.children:
        _walk(child, callback, level+1):

# public wrapper without the default param
def walk(tree, callback):
    _walk(tree, callback)

哪,BTW,证明我们真的有另一个XY问题......


5
投票

Python没有静态变量by design。对于您的示例,并且通常在循环块等中使用,您只需在外部作用域中使用变量;如果这使得它太长寿,可能是时候考虑将该功能分解为较小的功能。

对于在函数调用之间继续存在的变量,这只是重新实现对象的基本思想和该对象的方法,所以你应该改为其中之一。


4
投票

您可以使用nonlocal创建一个闭包以使其可编辑(仅限python 3.x)。这是一个计算列表长度的递归函数的示例。

def recursive_len(l):
    res = 0
    def inner(l2):
        nonlocal res
        if l2:
            res += 1
            inner(l2[1:])
    inner(l)
    return res

或者,您可以为函数本身分配属性。使用here的技巧:

def fn(self):
    self.number_of_times += 1
fn.func_defaults = (fn,)
fn.number_of_times = 0

fn()
fn()
fn()
print (fn.number_of_times)

1
投票

您还可以使用global关键字:

def main(args):
    for i in xrange(10):
        print i
        global tmp 
        tmp = i

但要小心......在大多数情况下,它会增加比解决的问题更多的问题。


0
投票

在python中执行此操作的另一种基于函数的方法是:

def f(arg, static_var=[0]):
    static_var[0] += arg

static_var对象在函数定义中初始化,然后重用于所有调用时,它将像静态变量一样运行。请注意,您不能只使用int,因为它们是不可变的。

>>> def f(arg, static_var=[0]):
...         static_var[0] += arg
...         print(static_var[0])
... 
>>> f(1)
1
>>> f(2)
3
>>> f(3)
6
© www.soinside.com 2019 - 2024. All rights reserved.