http://stackoverflow.com/questions/279561/what-is-the-python-equivalent-of-static-variables-inside-a-function
http://stackoverflow.com/questions/279561/what-is-the-python-equivalent-of-static-variables-inside-a-function
As an example, I would like to be able to do something like:
class foo(object):
...
def bar(self):
self.bar.counter += 1
return self.bar.counter
bar.counter = 1
...
but, when I call foo().bar() I get:
AttributeError: instancemethod object has no attribute counter
My goal in doing this is to try to impress that the counter variable is local to the bar() method, and also to avoid cluttering my class namespace with yet another attribute. Is there a way to do this? Is there a more pythonic way of doing this?
In Python 3 your code would work, but in Python 2 there is some wrapping that takes place when methods are looked up.
Class vs Instance
- class level: storing counter with the function (either directly, or by using a mutable default) effectively makes it a class level attribute as there is only ever one of the function, no matter how many instances you have (they all share the same function object).
- instance level: to make counter an instance level attribute you have to create the function in __init__, then wrap it with functools.partial (so it behaves like a normal method), and then store it on the instance -- now you have one function object for every instance.
Class Level
The accepted practice for a static-like variable is to use a mutable default argument:
class foo(object):
...
def bar(self, _counter=[0]):
_counter[0] += 1
return _counter[0]
If you want it to be prettier you can define your own mutable container:
class MutableDefault(object):
def __init__(self, start=0):
self.value = start
def __iadd__(self, other):
self.value += other
return self
def value(self):
return self.value
and change your code like so:
class foo(object):
def bar(self, _counter=MutableDefault()):
_counter += 1
return _counter.value
Instance level
from functools import partial
class foo(object):
def __init__(self):
def bar(self, _counter=MutableDefault(1)): # create new bar each time
value = _counter.value
_counter += 1
return value
self.bar = partial(bar, self)
Summary
As you can see, readability took a serious hit when moving to instance level for counter. I strongly suggest you reevaluate the importance of emphasizing that counter is part of bar, and if it is truly important maybe making bar its own class whose instances become part of the instances of foo. If it s not really important, do it the normal way:
class foo(object):
def __init__(self):
self.bar_counter = 0
def bar(self):
self.bar_counter += 1
return self.bar_counter
http://stackoverflow.com/questions/9523370/adding-attributes-to-instance-methods-in-python