From: Steven D'Aprano on 2 Apr 2010 19:57 On Fri, 02 Apr 2010 12:39:16 -0700, Patrick Maupin wrote: > On Apr 2, 2:38 pm, Ethan Furman <et...(a)stoneleaf.us> wrote: [...] >> Sounds like a personal preference issue, rather than a necessary / >> unnecessary issue -- after all, if you call that function a thousand >> times, only once is mongo not defined... clearly the exception. ;) >> >> ~Ethan~ > > Well, I think the whole discussion has basically been about personal > preference. OTOH, but if you call the function a few million times, you > might find the cost of try/except to be something that you would rather > not incur -- it might become a performance issue rather than a personal > choice issue. The cost of a try...except is *very* low -- about the same as a pass statement: >>> from timeit import Timer >>> t1 = Timer("pass", "") >>> t2 = Timer("try:\n pass\nexcept Exception:\n pass", "") >>> min(t2.repeat())/min(t1.repeat()) 1.9227982449955801 Actually catching the exception, on the other hand, is quite expensive: >>> t1 = Timer("len('')", "") >>> t2 = Timer("try:\n len(0)\nexcept Exception:\n pass", "") >>> min(t2.repeat())/min(t1.repeat()) 10.598482743564809 The heuristic I use is, if I expect the try block to raise an exception more than about one time in ten, I change to an explicit test. In this case, since the exception should only be raised once, and then never again, I would use a try...except block. -- Steven
From: Patrick Maupin on 2 Apr 2010 20:25 On Apr 2, 6:57 pm, Steven D'Aprano <st...(a)REMOVE-THIS- cybersource.com.au> wrote: > On Fri, 02 Apr 2010 12:39:16 -0700, Patrick Maupin wrote: > > On Apr 2, 2:38 pm, Ethan Furman <et...(a)stoneleaf.us> wrote: > [...] > >> Sounds like a personal preference issue, rather than a necessary / > >> unnecessary issue -- after all, if you call that function a thousand > >> times, only once is mongo not defined... clearly the exception. ;) > > >> ~Ethan~ > > > Well, I think the whole discussion has basically been about personal > > preference. OTOH, but if you call the function a few million times, you > > might find the cost of try/except to be something that you would rather > > not incur -- it might become a performance issue rather than a personal > > choice issue. > > The cost of a try...except is *very* low -- about the same as a pass > statement: Agreed. In the example above, if frobnicate() is a null function, the try/except adds about 5% to execution time on my machine. If I were really worried about execution time, I would use a closure *for this particular example* as I mentioned elsewhere. However, the cost of the try/except is not zero, and when I have something I prefer looking at (the __getattr__ doesn't clutter up the main-line execution with conditionals for stuff that only gets used once at initialization) that is always known to be cheaper in execution, that's what I use. I suppose some people might not like looking at the __getattr__, but this is a memoization technique I use quite often, so I find it idiomatic. Regards, Pat
From: Terry Reedy on 2 Apr 2010 21:46 On 4/2/2010 6:59 PM, kj wrote: > In<Xns9D4EC021DC8EAduncanbooth(a)127.0.0.1> Duncan Booth<duncan.booth(a)invalid.invalid> writes: > >> class Spam(object): >> mongo = None >> def __call__(self, x, y, z): >> if self.mongo is None: >> self.mongo = heavy_lifting_at_runtime() >> return frobnicate(x, y, z, self.mongo) Unless one wants the intialization of mongo delayed in case spam is never called, it can go in __init__ instead. >> spam = Spam() > >> ham = spam(1, 2, 3) > > I really like this. Thanks. > >> That's natural and readable. > >> From reading this thread, and the "(a==b) ? 'Yes' : 'No'" one, the > inescapable conclusion is that "readability" (like beauty) is very > much in the eye of the beholder, or, in this case, in the eye of > Guido. > > ~K
From: Terry Reedy on 2 Apr 2010 21:48 On 4/2/2010 1:28 PM, Paul McGuire wrote: > 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_ In 3.1, at least, the wrapper is not needed. def self_aware(fn): fn.__globals__["this"] = fn return fn Acts the same > @self_aware > def foo(): > this.counter += 1 > print this.counter > > foo.counter = 0 Explicit and separate initialization is a pain. This should be in a closure or class. > foo() > foo() > foo() > Prints: > 1 > 2 > 3 However, either way, the __globals__ attribute *is* the globals dict, not a copy, so one has >>> this <function foo at 0x00F5F5D0> Wrapping a second function would overwrite the global binding. Terry Jan Reedy
From: Ethan Furman on 2 Apr 2010 22:42
Terry Reedy wrote: >> In<Xns9D4EC021DC8EAduncanbooth(a)127.0.0.1> Duncan >> Booth<duncan.booth(a)invalid.invalid> writes: >> >>> class Spam(object): >>> mongo = None >>> def __call__(self, x, y, z): >>> if self.mongo is None: >>> self.mongo = heavy_lifting_at_runtime() >>> return frobnicate(x, y, z, self.mongo) > > > Unless one wants the intialization of mongo delayed in case spam is > never called, it can go in __init__ instead. As a matter of fact, I have an object that is usually not called during it's modules use, so I put in __getattr__. Sped the modules load time back up to pert near instantaneous. :) ~Ethan~ |