I like it. I'm not fully competent to comment on the details, but a big +1 for something like this, if not this.<br><br>-T<br><br><div class="gmail_quote">On Thu, Aug 20, 2009 at 9:07 AM, Jeff McAninch <span dir="ltr"><<a href="mailto:mcaninch@lanl.gov">mcaninch@lanl.gov</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">



<div bgcolor="#ffffff" text="#000000">
<tt>I would like to propose an expression, similar to the if-else
expression,<br>
that responds to exceptions.<br>
<br>
I had originally posted this (probably mistakenly) on py-dev.  This
current posting is a cleaned up<br>
version of the idea, based on responses I got on from the earlier
posting.<br>
<br>
<u><b>Abstract:<br>
</b></u><font color="#3333ff">Proposal for a conditional expression,
similar to the if-else expression, that responds to exceptions.<br>
</font><br>
<u><b>Motivation:<br>
</b></u><font color="#3333ff">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.<br>
</font><br>
<u><b>Very Simple Example - type coercion:<br>
</b></u>Current approach:<br>
<font color="#3333ff">    try:<br>
        x = float(string)<br>
    except:<br>
        x = float('nan')<br>
<br>
</font>Proposed solution using exception-based conditional expression:<br>
<font color="#3333ff">    x = float(string) except ValueError:
float('nan')<br>
</font><br>
<br>
<u><b>Simple Example - type coercion in a list comprehension:<br>
</b></u>Current approach:<br>
<font color="#3333ff">    def safe_float(string):<br>
        try:<br>
            x = float(string)<br>
        except ValueError:<br>
            x = float('nan')<br>
        return x<br>
    ...<br>
    xs = (safe(float(string)) for string in strings)<br>
</font><br>
</tt><tt>Proposed solution using exception-based conditional expression:<br>
</tt><tt><font color="#3333ff">    xs = ((float(string) except
ValueError: float('nan')) for string in strings)<br>
</font><br>
<u><b>Discussion:<br>
</b></u>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.)<br>
<br>
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":<br>
<font color="#3333ff">    xs = (operation_A(x) for x in ys)<br>
    xs = (operation_B(x) for x in xs if filter_B(x))<br>
    xs = (operation_C(x) if (some_condition(x)) else operation_D(x) for
x in xs if filter_C(x))<br>
    # final, explicit list of values<br>
    xs = [ x for x in xs ]<br>
</font>This is often a flexible way for me to define processing and
filtering sequences which also seems<br>
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<br>
into many of these process sequences, keeping them both robust and
flexible.<br>
</tt><tt><font color="#3333ff">    xs = (operation_N(x) except
exceptionN: operation_Nprime(x) for x in xs)<br>
</font></tt><br>
<tt>I also often have object classes which have some common method or
attribute.  For instance, some of my objects have scope-dependent
values:<br>
<font color="#3333ff">    x = y.evaluate(scope))<br>
</font>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:<br>
<font color="#3333ff">    x = y.evaluate(locals()) if ('evaluate' in
y.__dict__) else y<br>
</font>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.)<br>
<br>
I would much rather write:<br>
</tt><tt><font color="#3333ff">    x = y.evaluate(locals()) except
AttributeError: y<br>
</font></tt>or, in the list comprehension example:<br>
<tt><font color="#3333ff">    xs = (y.evaluate(locals()) except
AttributeError: y for y in ys)<br>
</font></tt><br>
Clearly this <tt>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:<br>
<font color="#3333ff">    def safe_evaluate(y,scope):<br>
       try:<br>
          x = y.evaluate(scope)<br>
       except AttributeError:<br>
          x = y<br>
       return x<br>
    ...<br>
    xs = (safe_evaluate(y,locals()) for y in ys)<br>
</font>but this quickly (in my packages at least) leads to an annoying
proliferation of "safe_" functions.<br>
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?).<br>
<br>
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:<br>
<font color="#3333ff">    x = expression0 except: default_expression<br>
</font></tt><font color="#3333ff"><tt>    x = expression0 except
exception1: expression1 except exception2: expression2 except: </tt></font><tt><font color="#3333ff">default_expression</font></tt><br>
<tt><br>
Or, more generally:<br>
</tt><font color="#3333ff"><tt>    x = expression0\<br>
            except exception1: expression1\<br>
            except exception2: expression2\<br>
            ...<br>
            except exceptionI: expressionI\<br>
            ...<br>
            except: </tt></font><tt><font color="#3333ff">default_expression</font></tt><br>
In this last example, the behaviour would be as follows:<br>
    - evaluate expression0.  <br>
            If no exception is encountered, return the result.<br>
    - if an exception is encountered, <br>
            search for the matching exception in the except clauses.<br>
    - if a matching exception ("exceptionI") is found, <br>
            evaluate the corresponding expression ("expressionI"), and
return the result.<br>
    - if no matching exception is found, and a default except: clause
(i.e., one without and exception)<br>
          is given, evaluate default_expression, and return the result.<br>
    - if no matching exception is found, and no default except clause
if given, <br>
          pass the exception on to the caller.<br>
    - if a new exception is encountered while evaluating an an except
expression ("expressionI"), <br>
          pass the exception on to the caller.<br>
<br>
I hope I have made a convincing case here.  This seems to me to be a
natural ("Pythonic") addition to the language.<br>
<br>
Jeff McAninch<br>
<br>
<pre cols="72">-- 
==========================
Jeffrey E. McAninch, PhD
Physicist, X-2-IFD
Los Alamos National Laboratory
Phone: 505-667-0374
Email: <a href="mailto:mcaninch@lanl.gov" target="_blank">mcaninch@lanl.gov</a>
==========================
</pre>
</div>

<br>_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
<a href="http://mail.python.org/mailman/listinfo/python-ideas" target="_blank">http://mail.python.org/mailman/listinfo/python-ideas</a><br>
<br></blockquote></div><br><br clear="all"><br>-- <br>--------------------------------------------------<br>Tennessee Leeuwenburg<br><a href="http://myownhat.blogspot.com/">http://myownhat.blogspot.com/</a><br>"Don't believe everything you think"<br>