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

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

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


当前回答

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 foo():
    try:
        foo.counter += 1
    except AttributeError:
        foo.counter = 1

推理:

非常python化(“请求原谅而不是允许”) 使用异常(只抛出一次)而不是if分支(考虑StopIteration异常)

其他解决方案将计数器属性附加到函数,通常使用复杂的逻辑来处理初始化。这对于新代码是不合适的。

在Python 3中,正确的方法是使用非局部语句:

counter = 0
def foo():
    nonlocal counter
    counter += 1
    print(f'counter is {counter}')

有关非局部语句的规范,请参阅PEP 3104。

如果计数器是模块私有的,则应该将其命名为_counter。

当然,这是一个老问题,但我想我可以提供一些更新。

看来性能论点已经过时了。 对于siInt_try和isInt_re2,相同的测试套件似乎给出了类似的结果。 当然,结果会有所不同,但这是在我的计算机上使用python 3.4.4的一次会话,使用Xeon W3550的内核4.3.01。 我已经运行了几次,结果似乎相似。 我将全局正则表达式移动到函数静态,但性能差异可以忽略不计。

isInt_try: 0.3690
isInt_str: 0.3981
isInt_re: 0.5870
isInt_re2: 0.3632

考虑到性能问题,try/catch似乎可以生成最适合未来和墙角情况的代码,所以可能只是将其包装在函数中

您可以向函数添加属性,并将其用作静态变量。

def myfunc():
  myfunc.counter += 1
  print myfunc.counter

# attribute must be initialized
myfunc.counter = 0

或者,如果你不想在函数外部设置变量,你可以使用hasattr()来避免AttributeError异常:

def myfunc():
  if not hasattr(myfunc, "counter"):
     myfunc.counter = 0  # it doesn't exist yet, so initialize it
  myfunc.counter += 1

无论如何,静态变量是相当罕见的,您应该为这个变量找到一个更好的位置,最有可能是在类中。