[Python-ideas] exception based conditional expression, similar to if-else conditional expression

Calvin Spealman ironfroggy at gmail.com
Thu Aug 20 03:59:07 CEST 2009

-1 on colons in the expression like that. I like the idea of being
able to handle an exception in generator expressions and the like, but
I've never seen a syntax I liked. I think I've favored the idea of
something like `float(x) except float('nan') if ValueError` thinking
it reads more naturally as an expression, puts the real logic
("convert x to a float or get a NaN float") together, which I think
makes sense.

I fear being able to "express" too much. That is, we're going to
remove all that indentation gives us if eventually everything is given
an expression form.

Let's add an import expression, next. Maybe this?

sys.exit(1) from sys

Joke, obviously.

On Wed, Aug 19, 2009 at 7:07 PM, Jeff McAninch<mcaninch at lanl.gov> wrote:
> I would like to propose an expression, similar to the if-else expression,
> that responds to exceptions.
> I had originally posted this (probably mistakenly) on py-dev.  This current
> posting is a cleaned up
> version of the idea, based on responses I got on from the earlier posting.
> Abstract:
> Proposal for a conditional expression, similar to the if-else expression,
> that responds to exceptions.
> Motivation:
> An expression syntax that responds to exceptions, and which reproduces the
> readability and conciseness of the if-else conditional expression, would
> simplify some exception-handling cases, especially within list
> comprehensions.
> Very Simple Example - type coercion:
> Current approach:
>     try:
>         x = float(string)
>     except:
>         x = float('nan')
> Proposed solution using exception-based conditional expression:
>     x = float(string) except ValueError: float('nan')
> Simple Example - type coercion in a list comprehension:
> Current approach:
>     def safe_float(string):
>         try:
>             x = float(string)
>         except ValueError:
>             x = float('nan')
>         return x
>     ...
>     xs = (safe(float(string)) for string in strings)
> Proposed solution using exception-based conditional expression:
>     xs = ((float(string) except ValueError: float('nan')) for string in
> strings)
> Discussion:
> In my own python coding, I find I make common use of the if-else conditional
> expression, especially within list comprehensions.  (In one of my packages,
> which has ~5800 lines of code, I found if-else expressions in ~1% of the
> lines.)
> Here is a slightly more involved example than the examples presented above.
> In data processing, I often string together a sequence of iterable list
> comprehensions, corresponding to a sequence of operations on a given dataset
> "ys" to produce a processed dataset "x":
>     xs = (operation_A(x) for x in ys)
>     xs = (operation_B(x) for x in xs if filter_B(x))
>     xs = (operation_C(x) if (some_condition(x)) else operation_D(x) for x in
> xs if filter_C(x))
>     # final, explicit list of values
>     xs = [ x for x in xs ]
> This is often a flexible way for me to define processing and filtering
> sequences which also seems
> to have good performance on very large datasets.  One advantage is that I
> can quickly mix-and-match from existing processes like this to make a new
> process.  An exception-based conditional would go nicely
> into many of these process sequences, keeping them both robust and flexible.
>     xs = (operation_N(x) except exceptionN: operation_Nprime(x) for x in xs)
> I also often have object classes which have some common method or
> attribute.  For instance, some of my objects have scope-dependent values:
>     x = y.evaluate(scope))
> where scope is typically locals(), globals(), or some other dictionary-like
> container.  But, to keep my code modular, I want to handle, in the same
> lines of code, objects which do not have some particular method, which leads
> me to lines of code like:
>     x = y.evaluate(locals()) if ('evaluate' in y.__dict__) else y
> This seems not very "Pythonic", similar to using type-testing instead of
> try-except.  (My impression was that there was a long-standing trend in the
> evolution of Python to remove tests like this, and I thought that was the
> original motivation for the try-except syntax.)
> I would much rather write:
>     x = y.evaluate(locals()) except AttributeError: y
> or, in the list comprehension example:
>     xs = (y.evaluate(locals()) except AttributeError: y for y in ys)
> Clearly this can be handled in several ways with the language as it is.  One
> way is to define a new function, as in the second simple example above:
>     def safe_evaluate(y,scope):
>        try:
>           x = y.evaluate(scope)
>        except AttributeError:
>           x = y
>        return x
>     ...
>     xs = (safe_evaluate(y,locals()) for y in ys)
> but this quickly (in my packages at least) leads to an annoying
> proliferation of "safe_" functions.
> Again, this seems not to be in the "Pythonic" spirit, and is also less
> concise, less readable.  (I also suspect, but have not verified, that this
> is in general less efficient than in-line expressions -- wasn't that part of
> the original motivation for list comprehensions?).
> In the thread of my previous post to py-dev, there were comments, questions,
> and suggestions concerning the details of the syntax.  Having reflected on
> this for a couple weeks, I am now most strongly supportive of what is
> essentially just an inline compression of the current try-except syntax.  So
> the following examples would be allowed:
>     x = expression0 except: default_expression
>     x = expression0 except exception1: expression1 except exception2:
> expression2 except: default_expression
> Or, more generally:
>     x = expression0\
>             except exception1: expression1\
>             except exception2: expression2\
>             ...
>             except exceptionI: expressionI\
>             ...
>             except: default_expression
> In this last example, the behaviour would be as follows:
>     - evaluate expression0.
>             If no exception is encountered, return the result.
>     - if an exception is encountered,
>             search for the matching exception in the except clauses.
>     - if a matching exception ("exceptionI") is found,
>             evaluate the corresponding expression ("expressionI"), and
> return the result.
>     - if no matching exception is found, and a default except: clause (i.e.,
> one without and exception)
>           is given, evaluate default_expression, and return the result.
>     - if no matching exception is found, and no default except clause if
> given,
>           pass the exception on to the caller.
>     - if a new exception is encountered while evaluating an an except
> expression ("expressionI"),
>           pass the exception on to the caller.
> I hope I have made a convincing case here.  This seems to me to be a natural
> ("Pythonic") addition to the language.
> Jeff McAninch
> --
> ==========================
> Jeffrey E. McAninch, PhD
> Physicist, X-2-IFD
> Los Alamos National Laboratory
> Phone: 505-667-0374
> Email: mcaninch at lanl.gov
> ==========================
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> http://mail.python.org/mailman/listinfo/python-ideas

Read my blog! I depend on your acceptance of my opinion! I am interesting!
Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy

More information about the Python-ideas mailing list