The Python Oracle

What is the Python equivalent of static variables inside a function?

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Breezy Bay

--

Chapters
00:00 What Is The Python Equivalent Of Static Variables Inside A Function?
00:25 Accepted Answer Score 874
00:57 Answer 2 Score 295
01:28 Answer 3 Score 268
01:50 Answer 4 Score 82
02:05 Answer 5 Score 62
02:29 Thank you

--

Full question
https://stackoverflow.com/questions/2795...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #static

#avk47



ACCEPTED ANSWER

Score 874


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)




ANSWER 2

Score 295


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.




ANSWER 3

Score 270


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)



ANSWER 4

Score 62


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.