[Python-ideas] if expensive_computation() as x:

Steven D'Aprano steve at pearwood.info
Fri Feb 14 21:38:14 CET 2014


On Fri, Feb 14, 2014 at 07:49:02AM +0100, Michele Lacchia wrote:
> You could gather all the functions in a list and then iterate and break
> when needed:
> 
> for func in [f1, f2, f3, f4]:
>     x = func()
>     if x:
>         # bla bla
>         break

To me, that is the cleanest, most obvious solution to avoid repeating 
yourself. Must nicer than the suggestion to add name binding to 
arbitrary expressions.

The only downside is that it assumes the "bla bla" part is identical for 
each function.


Coming back to Ram's suggestion:

> >     if expensive_computation_0():
> >         x = expensive_computation_0()
> >         # Do something with x...
> >     elif expensive_computation_1():
> >         x = expensive_computation_1()
> >         # Do something with x...
> >     elif expensive_computation_2():
> >         x = expensive_computation_2()
> >         # Do something with x...
> >
> > The problem here is that we're doing the expensive computation twice.

It's not really a language problem. The problem is not the lack of 
syntax, but the poor way the code is written, avoiding taking advantage 
of Python's already existing features. Put the code inside a function, 
assign the expensive computations once each time, and return as needed:

def perform_expensive_calculation():
    x = expensive_computation_0()
    if x:
        # Do something with x...
        return
    x = expensive_computation_1()
    if x:
        # Do something with x...
        return


This requires no new syntax, and it is easy to understand. If the "do 
something" parts include returning a value, you can drop the bare 
returns as well.


> > Obviously this can be "solved", i.e. rewritten in a way that wouldn't call
> > the expensive operation twice, but the solution would probably be quite
> > verbose, which is something we don't want.

It's not at all verbose. Apart from the extra returns, which are only 
needed if you're not otherwise returning from the "do something" parts, 
it is no more verbose than what you already have.


> > My suggestion:
> >
> >     if expensive_computation_0() as x:
> >         # Do something with x...

If we must have an alternative name binding of expressions, I don't mind 
this too much. But I'm not sold that this is needed.


> > If you'd like to bind to a variable only a part of the condition, this
> > would work too:
> >
> >     if x<5 with expensive_computation_0() as x:
> >         # Do something with x

I think that's hard to understand, unnecessary and clashes with the 
existing use of "with". It also leads to the possibility of abuse:

x < 5 with (y + 1)/y with z*(z+1) with function(arg) as z as y as x



-- 
Steven


More information about the Python-ideas mailing list