What Is the Python Equivalent of Static Variables Inside a Function

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

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)

static variables inside a python method

In python 2, you have to deal with bound and unbound methods. These do not have a __dict__ attribute, like functions do:

#python 2
'__dict__' in dir(SomeClass.some_method)
Out[9]: False

def stuff():
pass

'__dict__' in dir(stuff)
Out[11]: True

In python 3, your code works fine! The concept of bound/unbound methods is gone, everything is a function.

#python 3
'__dict__' in dir(SomeClass.some_method)
Out[2]: True

Back to making your code work, you need to put the attribute on the thing which has a __dict__: the actual function:

if not hasattr(SomeClass.some_method.__func__, 'some_static_var'):
#etc

Read more on im_func and __func__ here

It is up to you to decide whether this makes your code more or less readable - for me, making these types of things class attributes is almost always the way to go; it doesn't matter that only one method is accessing said attribute, it's where I look for "static" type vars. I value readable code over clean namespaces.

This last paragraph was of course an editorial, everyone is entitled to their opinion :-)

C-like Static Variable inside a Python class method

One way to achieve this is to tuck your variable away in a closure, so it will effectively be static for your purposes. Unfortunately, Python 2 does not support the nonlocal keyword, so we have to wrap our variable's value in an object (unless you only mean to reference and not mutate the variable (i.e. assign to the variable) in the method:

In [7]: class _Nonlocal:
...: def __init__(self, value):
...: self.counter = value
...:
...: def foo_maker():
...: nonlocal = _Nonlocal(0)
...: def foo(self):
...: nonlocal.counter += 1
...: print "You have called me {} times.".format(nonlocal.counter)
...: return foo
...:

In [8]: class Dummy(object): #you should always inherit from object explicitely in python 2
...: foo = foo_maker()
...:

In [9]: dummy = Dummy()

In [10]: dummy.foo()
You have called me 1 times.

In [11]: dummy.foo()
You have called me 2 times.

Of course, this is a lot of rigamarole simply to avoid using an instance variable. Perhaps the best solution is to make your method a custom object, and you can implement the descriptor protocol to make it callable as a method, and it will be usable as an instance method if you'd like:

In [35]: import types
...:
...: class Foo(object):
...: def __init__(this):
...: this.counter = 0
...: def __call__(this, self):
...: this.counter += 1
...: print "You have called me {} times.".format(this.counter)
...: print "here is some instance state, self.bar: {}".format(self.bar)
...: def __get__(this, obj, objtype=None):
...: "Simulate func_descr_get() in Objects/funcobject.c"
...: if obj is None:
...: return this
...: return types.MethodType(this, obj)
...:

In [36]: class Dummy(object): #you should always inherit from object explicitely in python 2
...: foo = Foo()
...: def __init__(self):
...: self.bar = 42
...:

In [37]: dummy = Dummy()

In [38]: dummy.foo()
You have called me 1 times.
here is some instance state, self.bar: 42

In [39]: dummy.bar = 99

In [40]: dummy.foo()
You have called me 2 times.
here is some instance state, self.bar: 99

All of this would be highly irregular and confusing to someone else who is used to python conventions, although I hope you see, the Python data-model offers a lot of power to customize things.

note, i've used this as the name of the first argument to avoid confusion with self that will actually come from the object that Foo get's bound to as a method.

Again, I should reiterate, I would never do this. I would just use an instance variable, or perhaps a generator if your function needs to maintain state, and could be used as an iterator.

python3: is there a kind of static variable in Python?

The simple way would be to return a "generator" function that forms a closure over a local, then just manipulate the local:

def new_id_generator():
id = 0

def gen():
nonlocal id
id += 1
return id

return gen

g = new_id_generator()

print(g(), g()) # 1 2

Python - Static Variable inside Function

In a global function, you can refer directly to the function object by looking up the name.

This does not work in a method; you'd have to look the method up on the class instead:

LKTracker.track_points

This still won't do what you want, however, because you'd get a unbound method object at that moment:

>>> LKTracker.track_points
<unbound method LKTracker.track_points>

Method objects are created on demand (because functions are descriptors), and creating an attribute on a method object is futile; they generally only live for a short while.

You'd need to access the function instead:

>>> LKTracker.track_points.__func__
<function track_points at 0x103e7c500>

but you can do the same thing on self:

self.track_points.__func__

Now you can add a attribute:

track_points = self.track_points.__func__
if not hasattr(track_points, "gotInitialFeatures"):
track_points.gotInitialFeatures = None

if not track_points.gotInitialFeatures:
#do some stuff
track_points.gotInitialFeatures = True

But it would be much easier to just store that attribute on the class instead:

if not hasattr(LKTracker, 'gotInitialFeatures'):

Static variable in Python?

Assuming what you want is "a variable that is initialised only once on first function call", there's no such thing in Python syntax. But there are ways to get a similar result:

1 - Use a global. Note that in Python, 'global' really means 'global to the module', not 'global to the process':

_number_of_times = 0

def yourfunc(x, y):
global _number_of_times
for i in range(x):
for j in range(y):
_number_of_times += 1

2 - Wrap you code in a class and use a class attribute (ie: an attribute that is shared by all instances). :

class Foo(object):
_number_of_times = 0

@classmethod
def yourfunc(cls, x, y):
for i in range(x):
for j in range(y):
cls._number_of_times += 1

Note that I used a classmethod since this code snippet doesn't need anything from an instance

3 - Wrap you code in a class, use an instance attribute and provide a shortcut for the method:

class Foo(object):
def __init__(self):
self._number_of_times = 0

def yourfunc(self, x, y):
for i in range(x):
for j in range(y):
self._number_of_times += 1

yourfunc = Foo().yourfunc

4 - Write a callable class and provide a shortcut:

class Foo(object):
def __init__(self):
self._number_of_times = 0

def __call__(self, x, y):
for i in range(x):
for j in range(y):
self._number_of_times += 1


yourfunc = Foo()

4 bis - use a class attribute and a metaclass

class Callable(type):
def __call__(self, *args, **kw):
return self._call(*args, **kw)

class yourfunc(object):
__metaclass__ = Callable

_numer_of_times = 0

@classmethod
def _call(cls, x, y):
for i in range(x):
for j in range(y):
cls._number_of_time += 1

5 - Make a "creative" use of function's default arguments being instantiated only once on module import:

def yourfunc(x, y, _hack=[0]):
for i in range(x):
for j in range(y):
_hack[0] += 1

There are still some other possible solutions / hacks, but I think you get the big picture now.

EDIT: given the op's clarifications, ie "Lets say you have a recursive function with default parameter but if someone actually tries to give one more argument to your function it could be catastrophic", it looks like what the OP really wants is something like:

# private recursive function using a default param the caller shouldn't set
def _walk(tree, callback, level=0):
callback(tree, level)
for child in tree.children:
_walk(child, callback, level+1):

# public wrapper without the default param
def walk(tree, callback):
_walk(tree, callback)

Which, BTW, prove we really had Yet Another XY Problem...

Static class variables and methods in Python

Variables declared inside the class definition, but not inside a method are class or static variables:

>>> class MyClass:
... i = 3
...
>>> MyClass.i
3

As @millerdev points out, this creates a class-level i variable, but this is distinct from any instance-level i variable, so you could have

>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

This is different from C++ and Java, but not so different from C#, where a static member can't be accessed using a reference to an instance.

See what the Python tutorial has to say on the subject of classes and class objects.

@Steve Johnson has already answered regarding static methods, also documented under "Built-in Functions" in the Python Library Reference.

class C:
@staticmethod
def f(arg1, arg2, ...): ...

@beidy recommends classmethods over staticmethod, as the method then receives the class type as the first argument.

Can you access a static variable in another static variable in Python

When the line list_of_count_of_each_item_sold = [0] * Purchase.list_of_items is evaluated the scope is already inside the class, so there is no need to use Purchase.list_of_items. You can directly access list_of_items:

class Purchase:
list_of_items = ["Cake", "Soap", "Jam", "Cereal", "Hand Sanitizer", "Biscuits", "Bread"]
list_of_count_of_each_item_sold = [0] * list_of_items

Additonally to initialize list_of_count_of_each_item_sold correctly with a 0 for each item in list_of_items you have to multiply [0] with the length of list_of_items by using len().

class Purchase:
list_of_items = ["Cake", "Soap", "Jam", "Cereal", "Hand Sanitizer", "Biscuits", "Bread"]
list_of_count_of_each_item_sold = [0] * len(list_of_items)

static variable in a function with Python Decorator

Because:

def static_var(varname, value):
def decorate(func):
setattr(func, varname, value)
return func
return decorate


@static_var("counter", 0)
def foo():
foo.counter += 1
print "Counter is %d" % foo.counter

is equivalent to:

foo = static_var("counter", 0)(foo)

Notice that static_var() actually gets called? Now walk through your decorator; in fact step through it with import pdb; pdb.set_trace()

Decorators wrap other functions potentially either mutating them or
returning new functions or both.

See: Understanding Python Decorators in 12 easy steps

If we stick a few print(s) in your decorator watch what happens:

def static_var(varname, value):
print "1"

def decorate(func):
print "2"
setattr(func, varname, value)
return func
print "3"
return decorate


@static_var("counter", 0)
def foo():
foo.counter += 1
print "Counter is %d" % foo.counter


foo()
foo()

Output:

$ python foo.py
1
3
2
Counter is 1
Counter is 2

So as I said above; firstly static_var("counter", 0) is called;
then the return of that (which returns a function) is called with
foo as it's first argument which sets up the initial "counter" and
returns the same argument (the function foo).



Related Topics



Leave a reply



Submit