From: Steven D'Aprano on
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
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
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
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
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~