这个C/ c++代码在Python中的等效代码是什么?

void foo()
{
    static int counter = 0;
    counter++;
    printf("counter is %d\n", counter);
}

具体来说,如何在函数级别实现静态成员,而不是在类级别?将函数放入类中会改变什么吗?


当前回答

米格尔·安吉洛的自我重新定义解决方案甚至可以不需要任何装饰:

def fun(increment=1):
    global fun
    counter = 0
    def fun(increment=1):
        nonlocal counter
        counter += increment
        print(counter)
    fun(increment)

fun()    #=> 1
fun()    #=> 2
fun(10)  #=> 12

第二行必须进行调整,以获得有限的范围:

def outerfun():
    def innerfun(increment=1):
        nonlocal innerfun
        counter = 0
        def innerfun(increment=1):
            nonlocal counter
            counter += increment
            print(counter)
        innerfun(increment)

    innerfun()    #=> 1
    innerfun()    #=> 2
    innerfun(10)  #=> 12

outerfun()

装饰器的优点是,你不必额外注意你的施工范围。

其他回答

使用函数的属性作为静态变量有一些潜在的缺点:

每次要访问变量时,都必须写出函数的全名。 外部代码可以很容易地访问该变量并打乱值。

第二个问题的惯用python可能会用前导下划线来命名变量,以表明它不应该被访问,同时在事后保持它的可访问性。

使用闭包

另一种选择是使用词法闭包的模式,python 3中的nonlocal关键字支持这种模式。

def make_counter():
    i = 0
    def counter():
        nonlocal i
        i = i + 1
        return i
    return counter
counter = make_counter()

遗憾的是,我不知道如何将这个解决方案封装到装饰器中。

使用内部状态参数

另一种选择可能是使用未记录的参数作为可变值容器。

def counter(*, _i=[0]):
    _i[0] += 1
    return _i[0]

这是可行的,因为默认参数是在定义函数时计算的,而不是在调用函数时计算的。

更清洁的方法可能是使用容器类型而不是列表,例如:

def counter(*, _i = Mutable(0)):
    _i.value += 1
    return _i.value

但我不知道内置类型,清楚地传达的目的。

def staticvariables(**variables):
    def decorate(function):
        for variable in variables:
            setattr(function, variable, variables[variable])
        return function
    return decorate

@staticvariables(counter=0, bar=1)
def foo():
    print(foo.counter)
    print(foo.bar)

就像上面vincent的代码一样,这将被用作函数装饰器,静态变量必须以函数名作为前缀访问。这段代码的优点(尽管每个人都可以聪明地看出这一点)是你可以有多个静态变量,并以更常规的方式初始化它们。

米格尔·安吉洛的自我重新定义解决方案甚至可以不需要任何装饰:

def fun(increment=1):
    global fun
    counter = 0
    def fun(increment=1):
        nonlocal counter
        counter += increment
        print(counter)
    fun(increment)

fun()    #=> 1
fun()    #=> 2
fun(10)  #=> 12

第二行必须进行调整,以获得有限的范围:

def outerfun():
    def innerfun(increment=1):
        nonlocal innerfun
        counter = 0
        def innerfun(increment=1):
            nonlocal counter
            counter += increment
            print(counter)
        innerfun(increment)

    innerfun()    #=> 1
    innerfun()    #=> 2
    innerfun(10)  #=> 12

outerfun()

装饰器的优点是,你不必额外注意你的施工范围。

我个人更喜欢下面的装饰。各有各的。

def staticize(name, factory):
    """Makes a pseudo-static variable in calling function.

    If name `name` exists in calling function, return it. 
    Otherwise, saves return value of `factory()` in 
    name `name` of calling function and return it.

    :param name: name to use to store static object 
    in calling function
    :type name: String
    :param factory: used to initialize name `name` 
    in calling function
    :type factory: function
    :rtype: `type(factory())`

    >>> def steveholt(z):
    ...     a = staticize('a', list)
    ...     a.append(z)
    >>> steveholt.a
    Traceback (most recent call last):
    ...
    AttributeError: 'function' object has no attribute 'a'
    >>> steveholt(1)
    >>> steveholt.a
    [1]
    >>> steveholt('a')
    >>> steveholt.a
    [1, 'a']
    >>> steveholt.a = []
    >>> steveholt.a
    []
    >>> steveholt('zzz')
    >>> steveholt.a
    ['zzz']

    """
    from inspect import stack
    # get scope enclosing calling function
    calling_fn_scope = stack()[2][0]
    # get calling function
    calling_fn_name = stack()[1][3]
    calling_fn = calling_fn_scope.f_locals[calling_fn_name]
    if not hasattr(calling_fn, name):
        setattr(calling_fn, name, factory())
    return getattr(calling_fn, name)
_counter = 0
def foo():
   global _counter
   _counter += 1
   print 'counter is', _counter

Python习惯上使用下划线来表示私有变量。在C语言中,在函数内部声明静态变量的唯一原因是将它隐藏在函数之外,这并不是真正的Python惯用方法。