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

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

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


当前回答

使用generator函数生成迭代器。

def foo_gen():
    n = 0
    while True:
        n+=1
        yield n

然后像这样使用它

foo = foo_gen().next
for i in range(0,10):
    print foo()

如果你想要一个上限:

def foo_gen(limit=100000):
    n = 0
    while n < limit:
       n+=1
       yield n

如果迭代器终止(如上面的例子),您也可以直接遍历它,如

for i in foo_gen(20):
    print i

当然,在这些简单的情况下,最好使用xrange:)

这是yield statement的文档。

其他回答

下面是一个完全封装的版本,不需要外部初始化调用:

def fn():
    fn.counter=vars(fn).setdefault('counter',-1)
    fn.counter+=1
    print (fn.counter)

在Python中,函数是对象,我们可以简单地通过特殊属性__dict__向它们添加或修补成员变量。内置的vars()返回特殊属性__dict__。

EDIT:注意,与另一种try不同:除了AttributeError答案外,使用这种方法,变量将始终为初始化后的代码逻辑做好准备。我认为try:except AttributeError替代以下将不那么干和/或有尴尬的流程:

def Fibonacci(n):
   if n<2: return n
   Fibonacci.memo=vars(Fibonacci).setdefault('memo',{}) # use static variable to hold a results cache
   return Fibonacci.memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2)) # lookup result in cache, if not available then calculate and store it

EDIT2:当函数将从多个位置调用时,我只推荐上述方法。如果函数只在一个地方被调用,最好使用nonlocal:

def TheOnlyPlaceStaticFunctionIsCalled():
    memo={}
    def Fibonacci(n):
       nonlocal memo  # required in Python3. Python2 can see memo
       if n<2: return n
       return memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2))
    ...
    print (Fibonacci(200))
    ...

鉴于这个问题,我可以提出另一个可能更好用的替代方案,对方法和函数看起来都是一样的:

@static_var2('seed',0)
def funccounter(statics, add=1):
    statics.seed += add
    return statics.seed

print funccounter()       #1
print funccounter(add=2)  #3
print funccounter()       #4

class ACircle(object):
    @static_var2('seed',0)
    def counter(statics, self, add=1):
        statics.seed += add
        return statics.seed

c = ACircle()
print c.counter()      #1
print c.counter(add=2) #3
print c.counter()      #4
d = ACircle()
print d.counter()      #5
print d.counter(add=2) #7
print d.counter()      #8    

如果你喜欢这种用法,下面是它的实现:

class StaticMan(object):
    def __init__(self):
        self.__dict__['_d'] = {}

    def __getattr__(self, name):
        return self.__dict__['_d'][name]
    def __getitem__(self, name):
        return self.__dict__['_d'][name]
    def __setattr__(self, name, val):
        self.__dict__['_d'][name] = val
    def __setitem__(self, name, val):
        self.__dict__['_d'][name] = val

def static_var2(name, val):
    def decorator(original):
        if not hasattr(original, ':staticman'):    
            def wrapped(*args, **kwargs):
                return original(getattr(wrapped, ':staticman'), *args, **kwargs)
            setattr(wrapped, ':staticman', StaticMan())
            f = wrapped
        else:
            f = original #already wrapped

        getattr(f, ':staticman')[name] = val
        return f
    return decorator

Soulution n +=1

def foo():
  foo.__dict__.setdefault('count', 0)
  foo.count += 1
  return foo.count

使用generator函数生成迭代器。

def foo_gen():
    n = 0
    while True:
        n+=1
        yield n

然后像这样使用它

foo = foo_gen().next
for i in range(0,10):
    print foo()

如果你想要一个上限:

def foo_gen(limit=100000):
    n = 0
    while n < limit:
       n+=1
       yield n

如果迭代器终止(如上面的例子),您也可以直接遍历它,如

for i in foo_gen(20):
    print i

当然,在这些简单的情况下,最好使用xrange:)

这是yield statement的文档。

另一个(不推荐!)对https://stackoverflow.com/a/279598/916373这样的可调用对象的扭曲,如果您不介意使用一个时髦的调用签名的话

class foo(object):
    counter = 0;
    @staticmethod
    def __call__():
        foo.counter += 1
        print "counter is %i" % foo.counter

>>> foo()()
counter is 1
>>> foo()()
counter is 2