From: kj on


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.

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.)

Another approach would be to stuff the static values in the function's
__dict__. This is less satisfactory than the closure approach
because the "pseudo-static" variable is accessible from outside
the function, but the code is arguably a little more straightforward,
and one does not end up with the now useless one-time closure-generating
function kicking around. Here's another version of the function
above:

>>> def spam():
.... d = spam.__dict__
.... if not 's' in spam.__dict__:
.... spam.s = 1
.... print spam.s
.... spam.s += 1
....
>>> spam()
1
>>> spam()
2
>>> spam()
3

Besides the external accessibility issue, I don't like explictly
coding the name of the function within the function. Is there any
way to have the function access its own __dict__ without having to
explicitly code its name in its body? E.g., is there some generic
special variable that, within a function, refers to the function
object itself?

I'm sure that there are many other ways to skin this cat, especially
if one starts definining fancy callable classes and whatnot. But
is there a better *simple* way to achieve C-style static locals in
Python that does not require a lot of extra machinery?

TIA!

~K
From: Chris Rebert on
On Thu, Apr 1, 2010 at 3:34 PM, kj <no.email(a)please.post> wrote:
> When coding C I have often found static local variables useful for
> doing once-only run-time initializations.
<snip>
> Another approach would be to stuff the static values in the function's
> __dict__.  This is less satisfactory than the closure approach
> because the "pseudo-static" variable is accessible from outside
> the function, but the code is arguably a little more straightforward,
> and one does not end up with the now useless one-time closure-generating
> function kicking around.  Here's another version of the function
> above:
>
>>>> def spam():
> ...     d = spam.__dict__
> ...     if not 's' in spam.__dict__:
> ...         spam.s = 1
> ...     print spam.s
> ...     spam.s += 1
> ...
>>>> spam()
> 1
>>>> spam()
> 2
>>>> spam()
> 3
>
> Besides the external accessibility issue, I don't like explictly
> coding the name of the function within the function.  Is there any
> way to have the function access its own __dict__ without having to
> explicitly code its name in its body?  E.g., is there some generic
> special variable that, within a function, refers to the function
> object itself?

Nope. It's been proposed in that past
(http://www.python.org/dev/peps/pep-3130/), but that proposal was
rejected.

> I'm sure that there are many other ways to skin this cat, especially
> if one starts definining fancy callable classes and whatnot.  But
> is there a better *simple* way to achieve C-style static locals in
> Python that does not require a lot of extra machinery?

You can abuse the default argument value mechanism:

def spam(s_cell=[1]):
s = s_cell[0]
print s
s_cell[0] += 1

It's a bit less ugly when the value itself is mutable, which isn't the
case here with the integer.

Personally, I hate such abuse with a passion; I think a global
variable is clearest.

Cheers,
Chris
--
http://blog.rebertia.com
From: Steve Holden on
Chris Rebert wrote:
> On Thu, Apr 1, 2010 at 3:34 PM, kj <no.email(a)please.post> wrote:
>> When coding C I have often found static local variables useful for
>> doing once-only run-time initializations.
> <snip>
>> Another approach would be to stuff the static values in the function's
>> __dict__. This is less satisfactory than the closure approach
>> because the "pseudo-static" variable is accessible from outside
>> the function, but the code is arguably a little more straightforward,
>> and one does not end up with the now useless one-time closure-generating
>> function kicking around. Here's another version of the function
>> above:
>>
>>>>> def spam():
>> ... d = spam.__dict__
>> ... if not 's' in spam.__dict__:
>> ... spam.s = 1
>> ... print spam.s
>> ... spam.s += 1
>> ...
>>>>> spam()
>> 1
>>>>> spam()
>> 2
>>>>> spam()
>> 3
>>
>> Besides the external accessibility issue, I don't like explictly
>> coding the name of the function within the function. Is there any
>> way to have the function access its own __dict__ without having to
>> explicitly code its name in its body? E.g., is there some generic
>> special variable that, within a function, refers to the function
>> object itself?
>
> Nope. It's been proposed in that past
> (http://www.python.org/dev/peps/pep-3130/), but that proposal was
> rejected.
>
>> I'm sure that there are many other ways to skin this cat, especially
>> if one starts definining fancy callable classes and whatnot. But
>> is there a better *simple* way to achieve C-style static locals in
>> Python that does not require a lot of extra machinery?
>
> You can abuse the default argument value mechanism:
>
> def spam(s_cell=[1]):
> s = s_cell[0]
> print s
> s_cell[0] += 1
>
> It's a bit less ugly when the value itself is mutable, which isn't the
> case here with the integer.
>
> Personally, I hate such abuse with a passion; I think a global
> variable is clearest.

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.

If the function were instead a method then the instance namespace would
be the logical place to store the required data.

regards
Steve
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: Terry Reedy on
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
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

From: Patrick Maupin on
On Apr 1, 6:10 pm, Steve Holden <st...(a)holdenweb.com> wrote:
> Chris Rebert wrote:
> > Personally, I hate such abuse with a passion; I think a global
> > variable is clearest.
>
> 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.
>
> If the function were instead a method then the instance namespace would
> be the logical place to store the required data.

In some situations I will use either the default parameter
initialization Chris mentioned, or the closure mechanism that the OP
presented, but only on code that I am optimizing for speed (local
variable lookups, even in nested functions, being much faster than
global or instance lookups). If it doesn't need to go fast, globals
or instance variables are the way to go.

Pat