Is this Python "static variable" hack ok to use? [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
An oft-asked question is whether there is an equivalent to static variables inside functions in Python. There are many answers, such as creating wrapper classes, using nested functions, decorators, etc.
One of the most elegant solutions I found was this, which I have slightly modified:
def foo():
# see if foo.counter already exists
try: test = foo.counter
# if not, initialize it to whatever
except AttributeError: foo.counter = 0
# do stuff with foo.counter
.....
.....
Example:
static.py
def foo(x):
# see if foo.counter already exists
try: test = foo.counter
# if not, initialize it to whatever
except AttributeError: foo.counter = 0
foo.counter += x
print(foo.counter)
for i in range(10):
foo(i)
output
$ python static.py
0
1
3
6
10
15
21
28
36
45
Is there any reason I should avoid this method? How the heck does it work, anyway?

How does this work?
It works because the function's name is just another entry in the local scope, and the function is an object like everything else in Python, and can have arbitrary attributes set on it:
def foo():
# The foo function object has already been fully constructed
# by the time we get into our `try`
try: test = foo.counter # Only run when foo is invoked
except AttributeError: foo.counter = 0
foo.counter += 1
if hasattr(foo, 'counter'):
print('Foo has a counter attribute')
else:
# This prints out - we've parsed `foo` but not executed it yet
print('Foo.counter does not exist yet')
# Now, we invoke foo
foo()
if hasattr(foo, 'counter'):
# And from now on (until we remove the attribute)
# this test will always succeed because we've added the counter
# attribute to the function foo.
print('Foo has a counter attribute')
else:
print('Foo.counter does not exist yet') # No longer true

Why not this:
def foo(x):
foo.counter += x
print(foo.counter)
foo.counter = 0 # init on module import
And then:
for i in range(10):
foo(i)
I get the same output with py2.7, py3.4.

The solution you have works fine, but if you're after the most elegant solution you may prefer this (adapted from one of the answers you linked to):
def foo(x):
foo.counter = getattr(foo, 'counter', 0) + x
print(foo.counter)
for i in range(10):
foo(i)
It works essentially the same, but getattr returns a default value (of 0) that only applies if foo doesn't have the counter attribute.

In python, you would probably be much better served by using generator functions.
It enables multiple simultaneous scopes (each generator instance can have it's own instance of foo.counter).
The "static" variables are properly encapsulated within the scope of the function (foo.counter is actually in the outer scope (file-level scope)).
Here's an example of using two simultaneous generators, each with their own version of the counter variable (not possible with "static" variables).
def foo():
counter = 0
while True:
# You can yield None here if you don't want any value.
yield counter
counter += 1
gen1 = foo()
gen2 = foo()
gen1.next()
# 0
gen1.next()
# 1
gen2.next()
# 0
You can provide some initial values to the generator and also send data back into the generators as well.
def foo(x=0)
counter = x
val = 1
while True:
sent = (yield counter)
if sent is None:
counter += val
val = 1
else:
val = sent
gen1 = foo(3)
gen1.next()
# 3
gen1.send(3)
gen1.next()
# 6
gen1.next()
# 7
You can do much more than simply iterate a counter. Generators are a powerful tool in python and are much more flexible that simple "static" variables.

I feel like an object is exactly what you're looking for here. It's a bit of state attached to some actions (in this case one action) that use and manipulate that state. So why not:
class Foo(object):
def __init__(self, start=0):
self.counter = start
def foo(self, x):
self.counter += x
print(self.counter)
foo = Foo()
for i in range(10):
foo.foo(i)
As others have stated, if you really really want to avoid a class you can. A function is already an object and can have any attribute added to it, just like any ordinary object. But why would you really want that? I understand that writing a class for a single function feels a bit like overkill, but you have stated that your actual code has various operations that ensue. Without seeing the various operations and such, it does seem like you have a reasonable case for using a class here.

You might run into some issues was the test will look outside the function scope for a foo.counter if it doesn't find one in the function. Eg the following returns 101 instead of 1
class Bar():
counter = 100
class Hoo():
def foo(x):
# see if foo.counter already exists
try: test = foo.counter
# if not, initialize it to whatever
except AttributeError: foo.counter = 0
foo.counter += x
print(foo.counter)
# make an object called foo that has an attribute counter
foo = Bar()
# call the static foo function
Hoo.foo(1)

Related

C-like Static Variable inside a Python class method

After 20 years of C++ experience I am struggling to learn something of Python.
Now I'd like to have a method (a function inside a class) that has a "static" variable of its own, and not a static class variable.
Probably a pseudo code example can illustrate better what I want.
class dummy:
#staticmethod
def foo():
foo.counter += 1
print "You have called me {} times.".format(foo.counter)
foo.counter = 0
NOTE 1: I used #staticmethod just for simplicity, but this is irrelevant.
NOTE 2: This crashes with AttributeError: 'staticmethod' object has no attribute 'counter' but as I said above, this is a pseudo code to clarify my objective.
I have already learned that this works outside a class:
def foo():
foo.counter += 1
print "You have called me {} times.".format(foo.counter)
foo.counter = 0
But the same trick doesn't seem to work for member-functions.
Last minute information, I am restricted to using Python 2.7 (not my choice).
Is there any legal and reliable way to have a persistent variable (or constant) with scope restricted to the member-function scope?
Some relevant links
"What is the Python equivalent of static variables inside a function?":
https://stackoverflow.com/a/279586/466339
"There are no function-level static variables in Python":
https://code-maven.com/slides/python-programming/static-variable
Thanks in advance.
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.
No, there is not. You've already found the Python version: a class variable that you, the supreme overlord of class dummy development, will access only within function foo.
If it would help to know the rationale for this, you can start that path here. I expect that you've already been through much of this; however, this answer gives Python specifics for more Pythonic ways to implement what you need.
As #Prune already mentioned there is no real way of doing so.
However, if you want the static variable inside a method to be available only to the object it belongs to (as it is in C++ as far as I remember), you should define it in the constructor or as a class variable with a non-static method:
from __future__ import print_function
class dummy:
def __init__(self, counter=0):
self._foo_counter = 0
def foo(self):
self._foo_counter += 1
print("You have called me {} times.".format(self._foo_counter))
or:
class dummy:
def foo(self):
self._foo_counter += 1
print("You have called me {} times.".format(self._foo_counter))
_foo_counter = 0
This way, running:
x = dummy()
for _ in range(4):
x.foo()
y = dummy()
for _ in range(4):
y.foo()
Results in:
You have called me 1 times.
You have called me 2 times.
You have called me 3 times.
You have called me 4 times.
You have called me 1 times.
You have called me 2 times.
You have called me 3 times.
You have called me 4 times.
Note that the two versions do not behave in exactly the same way.
When you define _foo_counter in the class directly, you will have access to the _foo_counter variable both for the object (self._foo_counter) and for the class itself (dummy._foo_counter).
The dummy._foo_counter will be static for every use of the class and will persist across multiple instances of the class, so across multiple objects.
This is also the only variable that you can access if you use the #staticmethod decorator on dummy.foo():
class dummy:
#staticmethod
def foo():
dummy._foo_counter += 1
print("You have called me {} times.".format(dummy._foo_counter))
_foo_counter = 0
Here, self or _foo_counter will not be accessible, and your only option is to use the class-wide variable dummy._foo_counter (which, as already mentioned, you could use with methods not decorated with #staticmethod as well).
So that running again:
x = dummy()
for _ in range(4):
x.foo()
y = dummy()
for _ in range(4):
y.foo()
results in:
You have called me 1 times.
You have called me 2 times.
You have called me 3 times.
You have called me 4 times.
You have called me 5 times.
You have called me 6 times.
You have called me 7 times.
You have called me 8 times.
Using a mutable type as the default value for a keyword argument for your function is maybe the simplest approach:
class Dummy:
#staticmethod
def foo(_counter=[0]): # here using a list, but you could use a dictionary, or a deque
_counter[0] += 1
print "You have called me {} times.".format(_counter[0])
The rationale is that this variable is initialized only once; its latest value remains in the closure formed.
I already posted this in an old post, but nobody noticed it
As I have a different idiomatic objective with static variables, I would like to expose the following:
In a function, I want to initialize a variable only once with a calculated value which may be a bit costly.
As I love nice-writing, and being an old C-style programmer. I tried to define a macro-like writing:
def Foo () :
StaticVar( Foo, ‘Var’, CalculateStatic())
StaticVar( Foo, ‘Step’, CalculateStep())
Foo.Var += Foo.Step
print(‘Value of Var : ‘, Foo.Var)
Then, I wrote ‘StaticVar’ like this:
def StaticVar(Cls, Var, StaticVal) :
if not hasattr(Cls, Var) :
setattr(Cls, Var, StaticVal)
I can even write nicer code in Python:
def StaticVars(Cls, **Vars) :
for Var, StaticVal in Vars.items() :
if not hasattr(Cls, Var) :
setattr(Cls, Var, StaticVal)
def Foo () :
StaticVars( Foo, Var = CalculateStatic(),Step= CalculateStep()))
Foo.Var += Foo. Step
print(‘Value of Var : ‘, Foo.Var)
Sure, this is a nice way to write the code, but my objective (only one call of initialization functions) is not met (just add a print in the initialization function to see that the it is called often) ! The fact is that, in a function call, the parameter value is evaluated even before the function is called.
def CalculateStatic() :
print("Costly Initialization")
return 0
def CalculateStep() :
return 2
def Test() :
Foo()
Foo()
Foo()
>>> Test()
Costly Initialization
Value of Var : 2
Costly Initialization
Value of Var : 4
Costly Initialization
Value of Var : 6
To meet my objective, I’d rather write something like this:
def Foo () :
if not hasattr(Foo, ‘Var’) :
setattr ( Foo, ‘Var’, CalculateStatic())
setattr ( Foo, ‘Step’, CalculateStep())
Foo.Var += Foo. Step
print(‘Value of Var : ‘, Foo.Var)
>>> Test()
Costly Initialization
Value of Var : 2
Value of Var : 4
Value of Var : 6
And it could be “nicely written” like this (I used the underscore notation refering to “private == static”):
def StaticVars(Cls, **Vars) :
for Var, StaticVal in Vars.items() :
setattr(Cls, Var, StaticVal)
def Foo () :
_ = Foo
try :
__ = _.Var
except AttributeError : # The above code could only generate AttributeError Exception
# the following code is executed only once
StaticDefVars(_, Var= CalculateStatic(), Step = CalculateStep())
_.Var += _. Step
print(‘Value of Var : ‘, Foo.Var)
Attention must be paid to not put 'calculation code' in the 'try' clause which could generate extra 'AttributeError' exception.
Sure, if Python had had 'Marcro preprocessing', it would be even nicer
"'

List of objects function not working

Sorry for the title, I hope it reflects correctly my problem :
In the following code, I was expecting the result to be result 0 1 2 but instead I have 2 2 2. The code inside my_function seems to be interpreted with the last instance of obj. What is wrong ?
class Example:
def __init__(self, x):
self.x = x
def get(self):
return self.x
a_list = []
for index in range(3):
obj = Example(index)
def my_function(x):
#some stuff with x like obj.another_function(x)
return obj.get()
a_list.append(my_function)
for c in a_list:
print(c())
When you define this
def my_function():
return obj.get()
Python will understand that my_function should run the get() method of an object called obj and return the value. It won't know the value of obj and what the get() method does until you attempt to call it.
So, you are actually defining three different functions that will eventually do the same thing. And, in the end, running the same code thrice.
But why is the return 2 2 2?
Because after the last iteration, the value of obj is Example(2)* because you redefine its value at every iteration, and the last one remains.
*
because of this line obj = Example(index)
Understanding a few things about how python works will help you understand what's happening here. Here obj is a closure, closures are evaluated at call time, not when the function is defined so if I do this:
x = "hello"
def printX():
print x
x = "goodbye"
printX() # goodbye
I get "goodbye" because printX is referencing a global variable in my module, which changes after I create printX.
What you want to do is create a function with a closure that references a specific object. The functional way to do this is to create a function that returns another function:
x = "hello"
def makePrintX(a):
def printX():
# We print a, the object passed to `makePrintX`
print a
return printX
# x is evaluated here when it is still "hello"
myPrintX = makePrintX(x)
x = "goodbye"
myPrintX() # "hello"
If you're having trouble understanding the above example I would recommend reading up on python's scoping rules. For your example, you could do something like this:
class Example:
def __init__(self, x):
self.x = x
def get(self):
return self.x
def makeObjFunction(obj):
def objFunction(x):
return obj.get()
return objFunction
a_list = []
for index in range(3):
obj = Example(index)
my_function = makeObjFunction(obj)
a_list.append(my_function)
for c in a_list:
print(c("some value"))
You are appending three my_functions to the a_list which are all closures over the same Example object. Try:
def my_function():
return obj
<__main__.Example object at 0x0054EDF0>
<__main__.Example object at 0x0054EDF0>
<__main__.Example object at 0x0054EDF0>
You can see they have the same id so calling get() on each should give the same answer.
If you just append the obj.get function (and drop the my_function) it'll work fine.
a_list.append(obj.get)
....
0
1
2
Edit: You've updated your question so to let you do more stuff in my_function(). It's still basically a scoping problem.
def my_func_factory(p_obj):
def my_function(x):
#some stuff with x like obj.another_function(x)
return p_obj.get()
return my_function
for index in range(3):
obj = Example(index)
a_list.append(my_func_factory(obj))
Since my_function can't see obj being reassigned, each instance doesn't pick up the change.
I think append() during the for just append the function address in a_list[]. After for iteration, the a_list is really given the number. Then it discovers the address of my_function, and they get the number in my_function, this is, 2. That's why you get [2,2,2].
Or maybe, in my_function, function give the method of "obj". But for iteration change the "obj" memory address each time, so the symbol "obj" always aim to the newest object Example. Due to my_function always get "obj", you get the same number from the last object.

Send by ref/by ptr in python? [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 9 years ago.
i need help-i try to send value to method like in c++ by ref/by ptr
how can i do it?
to exmple:
def test(x):
x=3
x=2
test(x)
print(x)
In this case x a local variable in test method and will not change the "original" X
so how can i change the "original" X?
thanks
In some ways, all calls in Python are called with references. In fact, all variables are references in a sense. But some types, like int from your example, cannot be changed.
In the case of, say, a list, the functionality you're looking for is trivial:
def change_it(some_list):
some_list.append("world")
foo = ["hello"]
change_it(foo)
print(foo) # prints ['hello', 'world']
Note, however, that reassigning the parameter variable some_list does not change the value in the calling context.
If you're asking this question, though, you're probably looking to do something like set two or three variables using one function. In that case, you're looking for something like this:
def foo_bar(x, y, z):
return 2*x, 3*y, 4*z
x = 3
y = 4
z = 5
x, y, z = foo_bar(x, y, z)
print(y) # prints 12
Of course, you can do anything in Python, but that doesn't mean you should. In the fashion of the TV show Mythbusters, here's something that does what you're looking for
import inspect
def foo(bar):
frame = inspect.currentframe()
outer = inspect.getouterframes(frame)[1][0]
outer.f_locals[bar] = 2 * outer.f_locals[bar]
a = 15
foo("a")
print(a) # prints 30
or even worse:
import inspect
import re
def foo(bar):
# get the current call stack
my_stack = inspect.stack()
# get the outer frame object off of the stack
outer = my_stack[1][0]
# get the calling line of code; see the inspect module documentation
# only works if the call is not split across multiple lines of code
calling_line = my_stack[1][4][0]
# get this function's name
my_name = my_stack[0][3]
# do a regular expression search for the function call in traditional form
# and extract the name of the first parameter
m = re.search(my_name + "\s*\(\s*(\w+)\s*\)", calling_line)
if m:
# finally, set the variable in the outer context
outer.f_locals[m.group(1)] = 2 * outer.f_locals[m.group(1)]
else:
raise TypeError("Non-traditional function call. Why don't you just"
" give up on pass-by-reference already?")
# now this works like you would expect
a = 15
foo(a)
print(a)
# but then this doesn't work:
baz = foo_bar
baz(a) # raises TypeError
# and this *really*, disastrously doesn't work
a, b = 15, 20
foo_bar, baz = str, foo_bar
baz(b) and foo_bar(a)
print(a, b) # prints 30, 20
Please, please, please, don't do this. I only put it in here to inspire the reader to look into some of the more obscure parts of Python.
As far as I am aware, this doesn't exist in Python (although a similar thing occurs if you pass mutable objects to a function). You would do either
def test():
global x
x = 3
test()
or
def test(x):
return 3
x = test(x)
The second of these is much preferred.

Static member of a function in Python ? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Static class variables in Python
What is the Python equivalent of static variables inside a function?
How can I use static fields in Python ?
for example i want to count how many times the function has been called - how can i do this ?
If you wish to count how many times a method has been called, no matter which instance called it, you could use a class member like this:
class Foo(object):
calls=0 # <--- call is a class member
def baz(self):
Foo.calls+=1
foo=Foo()
bar=Foo()
for i in range(100):
foo.baz()
bar.baz()
print('Foo.baz was called {n} times'.format(n=foo.calls))
# Foo.baz was called 200 times
When you define calls this way:
class Foo(object):
calls=0
Python places the key-value pair ('calls', 0) in Foo.__dict__.
It can be accessed with Foo.calls.
Instances of Foo, such as foo=Foo(), can access it with foo.calls as well.
To assign new values to Foo.calls you must use Foo.calls = ....
Instances can not use foo.calls = ... because that causes Python to place a new and different key-value pair in foo.__dict__, where instance members are kept.
Here's a decorator adding counting to a function.
import functools
def count_calls(func):
#functools.wraps(func)
def decor(*args, **kwargs):
decor.count += 1
return func(*args, **kwargs)
decor.count = 0
return decor
Usage:
>>> #count_calls
... def foo():
... pass
...
>>> foo.count
0
>>> foo()
>>> foo.count
1
Here is some example counting the number of calls of all objects of the same class:
class Swallow():
i = 0 # will be used for counting calls of fly()
def fly(self):
Swallow.i += 1
And this is the proof:
>>> a = Swallow()
>>> b = Swallow()
>>> a.fly()
>>> a.i
1
>>> Swallow.i
1
>>> b.fly()
>>> b.i
2
>>> Swallow.i
2
so you can read it by giving the object name or class name.
Here's one simplistic way to do it:
def func():
if not hasattr(func, 'counter'):
func.counter = 0
func.counter += 1
counter = 0 # Not the same as `func.counter`
print(func.counter)
Or if you don't like the if being executed on every call, you can do:
def func():
func.counter += 1
print(func.counter)
func.counter = 0

Is it possible to make Python functions behave like instances?

I understand that functions can have attributes. So I can do the following:
def myfunc():
myfunc.attribute += 1
print(myfunc.attribute)
myfunc.attribute = 1
Is it possible by any means to make such a function behave as if it were an instance? For example, I'd like to be able to do something like this:
x = clever_wrapper(myfunc)
y = clever_wrapper(myfunc)
x.attribute = 5
y.attribute = 9
x() # I want this to print 6 (from the 5 plus increment)
y() # I want this to print 10 (from the 9 plus increment)
As it stands, there is only one "instance" of the function, so attribute only exists once. Modifying it by either x or y changes the same value. I'd like each of them to have their own attribute. Is that possible to do at all? If so, can you provide a simple, functional example?
It is important that I be able to access attribute from inside of the function but have the value of attribute be different depending on which "instance" of the function is called. Essentially, I'd like to use attribute as if it were another parameter to the function (so that it could change the behavior of the function) but not pass it in. (Suppose that the signature of the function were fixed so that I cannot change the parameter list.) But I need to be able to set the different values for attribute and then call the functions in sequence. I hope that makes sense.
The main answers seem to be saying to do something like this:
class wrapper(object):
def __init__(self, target):
self.target = target
def __call__(self, *args, **kwargs):
return self.target(*args, **kwargs)
def test(a):
return a + test.attribute
x = wrapper(test)
y = wrapper(test)
x.attribute = 2
y.attribute = 3
print(x.attribute)
print(y.attribute)
print(x(3))
print(y(7))
But that doesn't work. Maybe I've done it incorrectly, but it says that test does not have attribute. (I'm assuming that it's because wrapper actually has the attribute.)
The reason I need this is because I have a library that expects a function with a particular signature. It's possible to put those functions into a pipeline of sorts so that they're called in order. I'd like to pass it multiple versions of the same function but change their behavior based on an attribute's value. So I'd like to be able to add x and y to the pipeline, as opposed to having to implement a test1 function and a test2 function that both do almost exactly the same thing (except for the value of the attribute).
You can make a class with a __call__ method which would achieve a similar thing.
Edit for clarity: Instead of making myfunc a function, make it a callable class. It walks like a function and it quacks like a function, but it can have members like a class.
A nicer way:
def funfactory( attribute ):
def func( *args, **kwargs ):
# stuff
print( attribute )
# more stuff
return func
x = funfactory( 1 )
y = funfactory( 2 )
x( ) # 1
y( ) # 2
This works because the functions are closures, so they will grab all local variables in their scope; this causes a copy of attribute to be passed around with the function.
class Callable(object):
def __init__(self, x):
self.x = x
def __call__(self):
self.x += 1
print self.x
>> c1 = Callable(5)
>> c2 = Callable(20)
>> c1()
6
>> c1()
7
>> c2()
21
>> c2()
22
A generator might be an alternate solution here:
def incgen(init):
while True:
init += 1
print init
yield
x = incgen(5)
y = incgen(9)
x.next() # prints 6
y.next() # prints 10
y.next() # prints 11
x.next() # prints 7
You can't dig back in to the generator and manipulate the data though.
#!/usr/bin/env python
# encoding: utf-8
class Callable(object):
attribute = 0
def __call__(self, *args, **kwargs):
return self.attribute
def main():
c = Callable()
c.attribute += 1
print c()
if __name__ == '__main__':
main()

Categories

Resources