From: Steve Holden on 1 Apr 2010 19:48 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 1 Apr 2010 21:37 * 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 1 Apr 2010 23:32 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 2 Apr 2010 12:08 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 2 Apr 2010 13:28
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 |