[Python-ideas] exception based conditional expression, similar to if-else conditional expression
ilya
ilya.nikokoshev at gmail.com
Sat Aug 22 11:36:26 CEST 2009
I like your use case, but it appears to me a processing task that
repeats a lot deserves its own function, so:
xs = apply(operation_N, {exceptionN: operation_Nprime}, xs)
which also happens to be shorter than
xs = (operation_N(x) except exceptionN: operation_Nprime(x) for x in xs)
Similarly, multiline try/except as in your last example
x = expression0\
except exception1: expression1\
except exception2: expression2\
...
except exceptionI: expressionI\
...
except: default_expression
is certainly useful. But we're lucky, nearly identical syntax already
exists out of the box!
try: _ = expression0
except exception1: _ = expression1
except exception2: _ = expression2
...
except exceptionI: _ = expressionI
...
except: _ = default_expression
x = _
What's so good about the your snippet that is bad about mine? Anyway,
instead of either of those I would prefer
# In most cases expression0 returns well-formed foo.
try: _ = expression0
except exception1: # Take care of the case of bar being not frobnicable.
_ = expression1
except exception2:
# This looks like magic, but is isn't. See documentation for
# exception2 at http:// some_url for explanation.
_ = expression2
...
except exceptionI: _ = expressionI
...
except exceptionLast:
_ = expressionLast
# All cases I could think of are exhausted! Of course, anything can
# happen so any other exception will propagate up.
x = _
On Thu, Aug 20, 2009 at 3:07 AM, 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
>
>
More information about the Python-ideas
mailing list