C-style static variables in Python?
Alf P. Steinbach
alfps at start.no
Thu Apr 1 21:37:58 EDT 2010
* kj:
> When coding C I have often found static local variables useful for
> doing once-only run-time initializations. For example:
>
> int foo(int x, int y, int z) {
>
> static int first_time = TRUE;
> static Mongo *mongo;
> if (first_time) {
> mongo = heavy_lifting_at_runtime();
> first_time = FALSE;
> }
>
> return frobnicate(mongo, x, y, z);
> }
>
> In this case, the static variable mongo is initialized only once
> (at most).
>
> What I like most about this is that it obviates the need for a
> global variable to hold the persistent value (I avoid globals like
> the plague, especially in Python). It also nicely encapsulates
> the logic that determines whether initialization is required.
In C++ you just write
int foo( int x, int y, int z )
{
static Mongo* const mongo = heavy_lifting_at_runtime();
return frobnicate( mongo, x, y, z );
}
> The best way I've found to achieve a similar effect in (procedural)
> Python defines the function as a closure. For example, here's a
> function that keeps track of (and prints out) how many times it
> has been called:
>
>>>> def make_spam():
> ... counter = [0]
> ... def _():
> ... counter[0] += 1
> ... print counter[0]
> ... return _
> ...
>>>> spam = make_spam()
>>>> spam()
> 1
>>>> spam()
> 2
>>>> spam()
> 3
>
> (Too bad that one can't stick the whole def inside parentheses and
> call the function right there, like one can do with JavaScript.)
Off the cuff, Py3:
class Spam:
def __init__( self ):
self._counter = 0
def __call__( self ):
self._counter += 1
print( counter )
spam = Spam()
spam()
spam()
spam()
[snip]
> I'm sure that there are many other ways to skin this cat, especially
> if one starts definining fancy callable classes and whatnot.
As I see it it's the closure that's fancy, and the class that's simple and direct.
> But
> is there a better *simple* way to achieve C-style static locals in
> Python that does not require a lot of extra machinery?
If you often need this functionality you might consider a general decorator that
supplies the function with a self argument, e.g. like this:
<example>
#Py3
class Object: pass
def static_initialization( init_func ):
def self_aware( f ):
def wrapped( *args, **kwargs ):
return f( f, *args, **kwargs )
init_func( f )
return wrapped
o = Object()
o.body = self_aware
return o
# Example usage:
@static_initialization
def spam( self ):
self.counter = 0
@spam.body
def spam( self ):
self.counter += 1
print( self.counter )
spam()
spam()
spam()
</example>
But as mentioned, a class is (at least IMHO) simpler and more direct.
Cheers & hth.,
- Alf (department of disingenious solutions)
More information about the Python-list
mailing list