[Python-ideas] One-line "try with" statement

Steven D'Aprano steve at pearwood.info
Mon Mar 4 01:31:59 CET 2013


On 04/03/13 09:31, Bruce Leban wrote:

> The try/except pattern I want to optimize is
>
>      try:
>          x = expr1
>      except ValueError:
>          x = expr2
>
> For example:
>
>      expr1 except ValueError else expr2
> or
>      try expr1 except ValueError else expr2

That syntax gets a big NO from me, due to confusion with the none one-line try...except...else statement.

Written out in full, try blocks look something like this:

try:
     block
except ValueError:
     block
else:
     block
finally:
     block

where the else clause runs if no exception occurred. Inserting "else" into the one-liner form, when the "else" doesn't have the same meaning as "else" in the multiline form, is just confusing.

Also, I vote -1 on a one-line *statement* (as per the subject line). What's the point of saving one lousy line? We can already do a two-line form:

try: statement1
except ValueError: statement2


which is plenty compact enough.

But a try...except *expression*, I'm cautiously interested in that idea. It could be analogous to the if...else ternary operator:

     y = x + (expr1 if condition else expr2)


Something like this perhaps?

     y = x + (try expr1 except Exception: expr2)


If you want to catch multiple exceptions, you can use a tuple:

     y = x + (try expr1 except (Exception, AnotherException): expr2)


If you need to refer to the exception:

     y = x + (try expr1 except Exception as name: expr2)


Supporting multiple except clauses would soon get out of hand, I suggestion we restrict the expression form to only a single except clause. Likewise, the else and finally clauses don't really make sense in an expression.

This is what I expect the full syntax should be:

try_expr ::=  "try" expression "except" [expression ["as" target]] ":" expression


I'm conflicted about the bare except form. If I had the keys to the time machine, I'd remove bare exceptions from the language. But since they're already supported, I guess we should support it here too.

If the "as target" form is used, the name only exists inside the except clause and does not otherwise become visible in the local scope. But of course you can return the exception object should you so choose.


> This is particularly useful in cases like this:
>
>      a = ((try t.x except AttributeError else 0)
>           + (try t.y except AttributeError else 0)
>           + (try t.z except AttributeError else 0))

This example is not terribly convincing, since it can so easily be re-written:

     a = sum(getattr(t, name, 0) for name in "xyz")




-- 
Steven



More information about the Python-ideas mailing list