What is the idiomatic Python equivalent of this C/C++ code?
void foo()
{
static int counter = 0;
counter++;
printf("counter is %d\n", counter);
}
specifically, how does one implement the static member at the function level, as opposed to the class level? And does placing the function into a class change anything?
31 Answers 31
A bit reversed, but this should work:
def foo():
foo.counter += 1
print "Counter is %d" % foo.counter
foo.counter = 0
If you want the counter initialization code at the top instead of the bottom, you can create a decorator:
def static_vars(**kwargs):
def decorate(func):
for k in kwargs:
setattr(func, k, kwargs[k])
return func
return decorate
Then use the code like this:
@static_vars(counter=0)
def foo():
foo.counter += 1
print "Counter is %d" % foo.counter
It'll still require you to use the foo.
prefix, unfortunately.
(Credit: @ony)
10 Comments
if "counter" not in foo.__dict__: foo.counter = 0
as the first lines of foo()
. This would help to avoid code outside the function. Not sure if this was possible back in 2008 though. P.S. Found this answer while searching for possibility to create static function variables, so this thread is still "alive" :)foo
and foo.counter =
are intimately related. however, I ultimately prefer the decorator approach, as there's no way the decorator will not be called and it is semantically more obvious what it does (@static_var("counter", 0)
is easier on & makes more sense to my eyes than if "counter" not in foo.__dict__: foo.counter = 0
, especially as in the latter you have to use the function name (twice) which might change).def foo():
if not hasattr(foo,"counter"): foo.counter=0
foo.counter += 1
You can add attributes to a function, and use it as a static variable.
def myfunc():
myfunc.counter += 1
print myfunc.counter
# attribute must be initialized
myfunc.counter = 0
Alternatively, if you don't want to setup the variable outside the function, you can use hasattr()
to avoid an AttributeError
exception:
def myfunc():
if not hasattr(myfunc, "counter"):
myfunc.counter = 0 # it doesn't exist yet, so initialize it
myfunc.counter += 1
Anyway static variables are rather rare, and you should find a better place for this variable, most likely inside a class.
7 Comments
try: myfunc.counter += 1; except AttributeError: myfunc.counter = 1
should do the same, using exceptions instead.try
add any cost? Just curious.One could also consider:
def foo():
try:
foo.counter += 1
except AttributeError:
foo.counter = 1
Reasoning:
- much pythonic ("ask for forgiveness not permission")
- use exception (thrown only once) instead of
if
branch (think StopIteration exception)
5 Comments
def fn(): if not hasattr(fn, 'c'): fn.c = 0
fn.c += 1 return fn.c
hasattr()
for this is not simpler and also less efficient.Many people have already suggested testing 'hasattr', but there's a simpler answer:
def func():
func.counter = getattr(func, 'counter', 0) + 1
No try/except, no testing hasattr, just getattr with a default.
4 Comments
try
/except
based approach is pretty meaningless. A simple ipython
%%timeit
microbenchmark gave the cost of the try
/except
at 255 ns per call, vs. 263 ns for the getattr
based solution. Yes, the try
/except
is faster, but it's not exactly "winning hands down"; it's a tiny micro-optimization. Write whatever code seems clearer, don't worry about trivial performance differences like this.Other answers have demonstrated the way you should do this. Here's a way you shouldn't:
>>> def foo(counter=[0]):
... counter[0] += 1
... print("Counter is %i." % counter[0]);
...
>>> foo()
Counter is 1.
>>> foo()
Counter is 2.
>>>
Default values are initialized only when the function is first evaluated, not each time it is executed, so you can use a list or any other mutable object to store static values.
11 Comments
def foo(arg1, arg2, _localstorage=DataClass(counter=0))
I find it well readable. Another good point is easy function renaming.types.SimpleNamespace
, making it def foo(arg1, arg2, _staticstorage=types.SimpleNamespace(counter=0)):
without needing to define a special class.Python doesn't have static variables but you can fake it by defining a callable class object and then using it as a function. Also see this answer.
class Foo(object):
# Class variable, shared by all instances of this class
counter = 0
def __call__(self):
Foo.counter += 1
print Foo.counter
# Create an object instance of class "Foo," called "foo"
foo = Foo()
# Make calls to the "__call__" method, via the object's name itself
foo() #prints 1
foo() #prints 2
foo() #prints 3
Note that __call__
makes an instance of a class (object) callable by its own name. That's why calling foo()
above calls the class' __call__
method. From the documentation:
Instances of arbitrary classes can be made callable by defining a
__call__()
method in their class.
7 Comments
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.
Comments
Other solutions attach a counter attribute to the function, usually with convoluted logic to handle the initialization. This is inappropriate for new code.
In Python 3, the right way is to use a nonlocal
statement:
counter = 0
def foo():
nonlocal counter
counter += 1
print(f'counter is {counter}')
See PEP 3104 for the specification of the nonlocal
statement.
If the counter is intended to be private to the module, it should be named _counter
instead.
4 Comments
global counter
statement instead of nonlocal counter
(nonlocal
just lets you write to closure state in a nested function). The reason people are attaching an attribute to the function is to avoid polluting the global namespace for state that's specific to the function, so you don't have to do even hackier things when two functions need independent counter
s. This solution doesn't scale; attributes on the function do. kdb's answer is how nonlocal
can help, but it does add complexity.nonlocal
over global
is exactly as you point out -- it works in strictly more circumstances.Using an attribute of a function as static variable has some potential drawbacks:
- Every time you want to access the variable, you have to write out the full name of the function.
- Outside code can access the variable easily and mess with the value.
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.
Using closures
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.
Using an internal state parameter
Another option might be an undocumented parameter serving as a mutable value container.
def counter(*, _i=[0]):
_i[0] += 1
return _i[0]
This works, because default arguments are evaluated when the function is defined, not when it is called.
Cleaner might be to have a container type instead of the list, e.g.
def counter(*, _i = Mutable(0)):
_i.value += 1
return _i.value
but I am not aware of a builtin type, that clearly communicates the purpose.
2 Comments
nonlocal
(first) method checks all the right boxes: the variable scope is the inner and outer functions but not global; the implementation fits inside the outer function definition; and it's straightforward for humans to read the code.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.
2 Comments
foo()
should re-initialize the dictionary to the value specified in the function definition (so with the counter key having a value of 0). Why it does not?_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.
Comments
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.
Comments
The idiomatic way is to use a class, which can have attributes. If you need instances to not be separate, use a singleton.
There are a number of ways you could fake or munge "static" variables into Python (one not mentioned so far is to have a mutable default argument), but this is not the Pythonic, idiomatic way to do it. Just use a class.
Or possibly a generator, if your usage pattern fits.
1 Comment
default
argument is the most elegant one.After trying several approaches I ended up using an improved version of @warvariuc's answer:
import types
def func(_static=types.SimpleNamespace(counter=0)):
_static.counter += 1
print(_static.counter)
Comments
Using a decorator and a closure
The following decorator can be used create static function variables. It replaces the declared function with the return from itself. This implies that the decorated function must return a function.
def static_inner_self(func):
return func()
Then use the decorator on a function that returns another function with a captured variable:
@static_inner_self
def foo():
counter = 0
def foo():
nonlocal counter
counter += 1
print(f"counter is {counter}")
return foo
nonlocal
is required, otherwise Python thinks that the counter
variable is a local variable instead of a captured variable. Python behaves like that because of the variable assignment counter += 1
. Any assignment in a function makes Python think that the variable is local.
If you are not assigning to the variable in the inner function, then you can ignore the nonlocal
statement, for example, in this function I use to indent lines of a string, in which Python can infer that the variable is nonlocal
:
@static_inner_self
def indent_lines():
import re
re_start_line = re.compile(r'^', flags=re.MULTILINE)
def indent_lines(text, indent=2):
return re_start_line.sub(" "*indent, text)
return indent_lines
P.S. There is a deleted answer that proposed the same. I don't know why the author deleted it. https://stackoverflow.com/a/23366737/195417
1 Comment
nonlocal
statement is not necessary if you can change the variable without assignment, i.e. if it is mutable.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
Comments
A global declaration provides this functionality. In the example below (python 3.5 or greater to use the "f"), the counter variable is defined outside of the function. Defining it as global in the function signifies that the "global" version outside of the function should be made available to the function. So each time the function runs, it modifies the value outside the function, preserving it beyond the function.
counter = 0
def foo():
global counter
counter += 1
print("counter is {}".format(counter))
foo() #output: "counter is 1"
foo() #output: "counter is 2"
foo() #output: "counter is 3"
1 Comment
Another (not recommended!) twist on the callable object like https://stackoverflow.com/a/279598/916373, if you don't mind using a funky call signature, would be to do
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
Comments
Instead of creating a function having a static local variable, you can always create what is called a "function object" and give it a standard (non-static) member variable.
Since you gave an example written C++, I will first explain what a "function object" is in C++. A "function object" is simply any class with an overloaded operator()
. Instances of the class will behave like functions. For example, you can write int x = square(5);
even if square
is an object (with overloaded operator()
) and not technically not a "function." You can give a function-object any of the features that you could give a class object.
# C++ function object
class Foo_class {
private:
int counter;
public:
Foo_class() {
counter = 0;
}
void operator() () {
counter++;
printf("counter is %d\n", counter);
}
};
Foo_class foo;
In Python, we can also overload operator()
except that the method is instead named __call__
:
Here is a class definition:
class Foo_class:
def __init__(self): # __init__ is similair to a C++ class constructor
self.counter = 0
# self.counter is like a static member
# variable of a function named "foo"
def __call__(self): # overload operator()
self.counter += 1
print("counter is %d" % self.counter);
foo = Foo_class() # call the constructor
Here is an example of the class being used:
from foo import foo
for i in range(0, 5):
foo() # function call
The output printed to the console is:
counter is 1
counter is 2
counter is 3
counter is 4
counter is 5
If you want your function to take input arguments, you can add those to __call__
as well:
# FILE: foo.py - - - - - - - - - - - - - - - - - - - - - - - - -
class Foo_class:
def __init__(self):
self.counter = 0
def __call__(self, x, y, z): # overload operator()
self.counter += 1
print("counter is %d" % self.counter);
print("x, y, z, are %d, %d, %d" % (x, y, z));
foo = Foo_class() # call the constructor
# FILE: main.py - - - - - - - - - - - - - - - - - - - - - - - - - - - -
from foo import foo
for i in range(0, 5):
foo(7, 8, 9) # function call
# Console Output - - - - - - - - - - - - - - - - - - - - - - - - - -
counter is 1
x, y, z, are 7, 8, 9
counter is 2
x, y, z, are 7, 8, 9
counter is 3
x, y, z, are 7, 8, 9
counter is 4
x, y, z, are 7, 8, 9
counter is 5
x, y, z, are 7, 8, 9
Comments
Soulution n +=1
def foo():
foo.__dict__.setdefault('count', 0)
foo.count += 1
return foo.count
Comments
Prompted by this question, may I present another alternative which might be a bit nicer to use and will look the same for both methods and functions:
@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
If you like the usage, here's the implementation:
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
Comments
This answer builds on @claudiu 's answer.
I found that my code was getting less clear when I always had to prepend the function name, whenever I intend to access a static variable.
Namely, in my function code I would prefer to write:
print(statics.foo)
instead of
print(my_function_name.foo)
So, my solution is to :
- add a
statics
attribute to the function - in the function scope, add a local variable
statics
as an alias tomy_function.statics
from bunch import *
def static_vars(**kwargs):
def decorate(func):
statics = Bunch(**kwargs)
setattr(func, "statics", statics)
return func
return decorate
@static_vars(name = "Martin")
def my_function():
statics = my_function.statics
print("Hello, {0}".format(statics.name))
Remark
My method uses a class named Bunch
, which is a dictionary that supports
attribute-style access, a la JavaScript (see the original article about it, around 2000)
It can be installed via pip install bunch
It can also be hand-written like so:
class Bunch(dict):
def __init__(self, **kw):
dict.__init__(self,kw)
self.__dict__ = self
1 Comment
types.SimpleNamespace
(available since 3.3) supports this behavior out of the box (and is implemented in C on CPython, so it's about as fast as it can be).Variant of the class method, makes the calling signature easier. using init means you don't need to use the () you need for _call, or create an instance of the class.
class do_work:
cnt=0
@staticmethod
def __init__(arg):
do_work.cnt += 1
print(arg, do_work.cnt)
do_work('a')
do_work('b')
do_work('e')
2 Comments
do_work(arg)
, you show use the (automatically @classmethod) __new__
method instead of __init__
; example in next comment.I personally prefer the following to decorators. To each their own.
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)
2 Comments
UPDATED: Just throwing my new implementation into the fray.
import functools
def staticinator(**kwargs):
""" Dr. Heinz Doofenshmirtz Approved Staticinator
Ah, Perry the Plateaus, you're just in time to witness my latest invention, the Staticinator!
It's a device that makes things static! Behold!
Allow me to explain my evil plan.
I will use the Staticinator to make all of my functions static. This will allow me to use
static variables in my functions. Mwahahahaha!
### Examples:
```python
>>> @staticinator(count=0)
... def _example_countinator(static: dict):
... static["count"] += 1
... return static["count"]
>>> _example_countinator()
1
>>> _example_countinator()
2
"""
def decoratinator(func):
partial_func = functools.partial(func, kwargs)
functools.update_wrapper(partial_func, func)
return partial_func
return decoratinator
This simple decorator allows you to initialize any number of variables as a static variable that will retain its value for subsequent executions.
Example 1
Here is a simple "counter" example
@staticinator(count=0)
def _example_count(static: dict):
"""A simple counter function that uses a static variable
### Examples:
```python
>>> _example_count()
1
>>> _example_count()
2
>>> _example_count()
3
```
"""
static["count"] += 1
return static["count"]
Example 2
How about something a bit more complex? Let's have an initial value set by the calling function that is subsequently cut in half.
@staticinator(value=None)
def _example_cut_it_in_half(static: dict, start_value: float = None) -> float:
"""Cut a value in half
### MEME
https://www.youtube.com/watch?v=uJ2LkrpmlaA
### Examples:
```python
>>> _example_cut_it_in_half(1000)
500.0
>>> _example_cut_it_in_half()
250.0
>>> _example_cut_it_in_half()
125.0
```
"""
if static["value"] is None:
static["value"] = start_value
static["value"] /= 2
return static["value"]
How it works
Just add the @staticinator
decorator to any function you want to add static variables to. Any variables defined are then passed as a dictionary as the first parameter of the decorated function. You can name this variable whatever you want but static
works as a means to keep things easy to understand.
We need to keep the values in the dictionary to ensure the reference remains intact. If we were to assign a value primitive to a variable, the magic would die and the variable would be a regular variable again.
You can even add keys to the static
dictionary and they would also be retained for subsequent calls.
Comments
Other posted answers are not compliant with mypy type checking. Using the vars() function to access the functions attributes dict results in compact code which mypy and other typecheckers will accept:
def get_static():
attrs = vars(get_static)
if attrs.setdefault("my_var", None) is None:
print("init")
attrs["my_var"] = 0
attrs["my_var"] += 1
return attrs["my_var"]
>>> get_static()
init
1
>>> get_static()
2
>>> get_static()
3
Comments
Building on Daniel's answer (additions):
class Foo(object):
counter = 0
def __call__(self, inc_value=0):
Foo.counter += inc_value
return Foo.counter
foo = Foo()
def use_foo(x,y):
if(x==5):
foo(2)
elif(y==7):
foo(3)
if(foo() == 10):
print("yello")
use_foo(5,1)
use_foo(5,1)
use_foo(1,7)
use_foo(1,7)
use_foo(1,1)
The reason why I wanted to add this part is , static variables are used not only for incrementing by some value, but also check if the static var is equal to some value, as a real life example.
The static variable is still protected and used only within the scope of the function use_foo()
In this example, call to foo() functions exactly as(with respect to the corresponding c++ equivalent) :
stat_c +=9; // in c++
foo(9) #python equiv
if(stat_c==10){ //do something} // c++
if(foo() == 10): # python equiv
#add code here # python equiv
Output :
yello
yello
if class Foo is defined restrictively as a singleton class, that would be ideal. This would make it more pythonic.
Comments
I write a simple function to use static variables:
def Static():
### get the func object by which Static() is called.
from inspect import currentframe, getframeinfo
caller = currentframe().f_back
func_name = getframeinfo(caller)[2]
# print(func_name)
caller = caller.f_back
func = caller.f_locals.get(
func_name, caller.f_globals.get(
func_name
)
)
class StaticVars:
def has(self, varName):
return hasattr(self, varName)
def declare(self, varName, value):
if not self.has(varName):
setattr(self, varName, value)
if hasattr(func, "staticVars"):
return func.staticVars
else:
# add an attribute to func
func.staticVars = StaticVars()
return func.staticVars
How to use:
def myfunc(arg):
if Static().has('test1'):
Static().test += 1
else:
Static().test = 1
print(Static().test)
# declare() only takes effect in the first time for each static variable.
Static().declare('test2', 1)
print(Static().test2)
Static().test2 += 1
Comments
Miguel Angelo's self-redefinition solution is even possible without any decorator:
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
The second line has to be adapted to get a limited scope:
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()
The plus of the decorator is that you don't have to pay extra attention to the scope of your construction.
Comments
I don't know how future-proof this solution is, so maybe it's only a curiosity. It exploits a python-gotcha that default parameters are only evaluated once.
def foo(counter=[0]):
counter[0] += 1
print(f"{counter[0] = }")
foo()
foo()
output is
counter[0] = 1
counter[0] = 2
obvious variants are
def foo(thing,counter={}):
if thing not in counter:
counter[thing] = 0
counter[thing] += 1
print(f"count of {thing} = {counter[thing]}")
return counter
foo('cat')
foo('cat')
foo('bird')
output is
count of cat = 1
count of cat = 2
count of bird = 1
def fib(answer=[]):
if len(answer)<2: # empty lists are not True
answer.append(1)
else:
answer.append(answer[-2]+answer[-1])
return answer[-1]
print(f"{[fib() for i in range(10)]}")
output is
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
_
prefix.