What is the idiomatic Python equivalent of this C/C++ code?
void foo()
{
static int counter = 0;
counter++;
A static variable inside a Python method
class Count:
def foo(self):
try:
self.foo.__func__.counter += 1
except AttributeError:
self.foo.__func__.counter = 1
print self.foo.__func__.counter
m = Count()
m.foo() # 1
m.foo() # 2
m.foo() # 3
A little bit more readable, but more verbose (Zen of Python: explicit is better than implicit):
>>> def func(_static={'counter': 0}):
... _static['counter'] += 1
... print _static['counter']
...
>>> func()
1
>>> func()
2
>>>
See here for an explanation of how this works.
_counter = 0 def foo(): global _counter _counter += 1 print 'counter is', _counter
Python customarily uses underscores to indicate private variables. The only reason in C to declare the static variable inside the function is to hide it outside the function, which is not really idiomatic Python.
Use a generator function to generate an iterator.
def foo_gen():
n = 0
while True:
n+=1
yield n
Then use it like
foo = foo_gen().next
for i in range(0,10):
print foo()
If you want an upper limit:
def foo_gen(limit=100000):
n = 0
while n < limit:
n+=1
yield n
If the iterator terminates (like the example above), you can also loop over it directly, like
for i in foo_gen(20):
print i
Of course, in these simple cases it's better to use xrange :)
Here is the documentation on the yield statement.
Using an attribute of a function as static variable has some potential drawbacks:
Idiomatic python for the second issue would probably be naming the variable with a leading underscore to signal that it is not meant to be accessed, while keeping it accessible after the fact.
An alternative would be a pattern using lexical closures, which are supported with the nonlocal
keyword in python 3.
def make_counter():
i = 0
def counter():
nonlocal i
i = i + 1
return i
return counter
counter = make_counter()
Sadly I know no way to encapsulate this solution into a decorator.
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)
Much like vincent's code above, this would be used as a function decorator and static variables must be accessed with the function name as a prefix. The advantage of this code (although admittedly anyone might be smart enough to figure it out) is that you can have multiple static variables and initialise them in a more conventional manner.