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