From: Steve Holden on
Terry Reedy wrote:
> On 4/1/2010 6:34 PM, kj wrote:
>>
>>
>> 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);
>
> Global var or class or closure such as below (obviously untested ;=):
>
> make_foo()
> mongo = heavy_lifting_at_runtime();
> def _(x,y,z):
> return frobnicate(mongo, x, y, z)
> return _
> foo = make_foo

I suspect you mean

foo = make_foo()

> del make_foo # to make sure it is *never* called again ;
>
> Now you only have foo with a hard-to-access private object and no
> first_time checks when you call it.
>
> Terry Jan Reedy
>
I don't think I'd ever want to use such an obscure technique in a
program. You might want to consider using functools.wraps to make sure
that the foo function looks right.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
See PyCon Talks from Atlanta 2010 http://pycon.blip.tv/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/

From: Alf P. Steinbach on
* 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)
From: Paul Rubin on
kj <no.email(a)please.post> writes:
> 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) { ...


Here are some cheesy ways.

1. Put an attribute onto the function name:

def foo(x, y, z):
if foo.first_time:
foo.mongo = heavy_lifting_at_runtime()
foo.first_time = False
...
foo.first_time = True

2. Use a mutable keyword parameter:

def foo(x, y, z, wrapped_mongo=[]):
if len(wrapped_mongo) == 0:
wrapped_mongo.append(heavy_lifting_at_runtime())
mongo = wrapped_mongo[0]
...

3. Streamline the first method a little:

def foo(x, y, z):
if len(foo.wrapped_mongo == 0):
foo.wrapped_mongo.append(heavy_lifting_at_runtime())
mongo = foo.wrapped_mongo[0]
...
foo.wrapped_mongo = []

All of these of course don't give as good encapsulation as one might
like.
From: kj on
In <mailman.1437.1270163476.23598.python-list(a)python.org> Steve Holden <steve(a)holdenweb.com> writes:

>But the real problem is that the OP is insisting on using purely
>procedural Python when the problem is screaming for an object-oriented
>answer.

My initial reaction to this comment was something like "What? switch
from procedural to OO just to be able to do some one-time initialization
of function-private data???" But then, again, since Python allows
easy mixing of both programming styles, I suppose one could refactor this:

<procedural>
def spam(x, y, z):
try:
mongo = spam.mongo
except AttributeError:
mongo = spam.mongo = heavy_lifting_at_runtime()
return frobnicate(x, y, z, mongo)

ham = spam(3, 4, 5)
</procedural>

into this:

<OO>
class _Spam(object):
@classmethod
def _(cls, x, y, z):
try:
mongo = cls.mongo
except AttributeError:
mongo = cls.mongo = heavy_lifting_at_runtime()
return frobnicate(x, y, z, mongo)

ham = _Spam._(1, 2, 3)
</OO>


Is this really more natural or more readable? Hmmm.

In any case, the first solution does rely on the fact that functions
are objects, and therefore can have attributes, so even the
"procedural" version relies on Python's OO model.

Other responses advocated for global variables. I avoid them in
general, and doubly so in Python, because I find Python's shenanigans
with globals mystifying (this business of becoming silently local
if assigned to); it's one rare instance in which Python out-Perls
Perl. And yes, I know that the language includes ways to deal with
this (with the global keyword, etc.) but I find the whole scheme
is so much "cutting against the grain".

Thanks for all the replies. There are a lot of good ideas there.
I'm particular, I'm thankful for the pointers to PEP 3130 (initial
reaction: maybe I should learn Dutch) and to functools.wraps, and
for the code snippets.

~K
From: Paul McGuire on
On Apr 1, 5:34 pm, kj <no.em...(a)please.post> wrote:
> When coding C I have often found static local variables useful for
> doing once-only run-time initializations.  For example:
>

Here is a decorator to make a function self-aware, giving it a "this"
variable that points to itself, which you could then initialize from
outside with static flags or values:

from functools import wraps

def self_aware(fn):
@wraps(fn)
def fn_(*args):
return fn(*args)
fn_.__globals__["this"] = fn_
return fn_

@self_aware
def foo():
this.counter += 1
print this.counter

foo.counter = 0

foo()
foo()
foo()


Prints:

1
2
3

-- Paul