[Python-ideas] except expression

Steven D'Aprano steve at pearwood.info
Sat Feb 15 19:11:39 CET 2014


On Sat, Feb 15, 2014 at 11:20:13AM +1300, Greg Ewing wrote:
> Here's another one:
> 
>    things[i] (except IndexError: 42)

I believe Jan Kaliszewski independently came up with the same syntax 
earlier, which is a good sign. Two people suggesting the same thing is 
promising.

Jan also suggested that this syntax allows binding the exception:

    things[i] (except IndexError as exc: exc.args)

and multiple except terms:

    things[i] (except IndexError as exc: exc.args,
               except NameError: "missing",
               except KeyError: None,
               )


One might also catch multiple exceptions in a single term:

    things[i] (except IndexError,KeyError as exc: exc.args)


It's a tiny bit unusual to have a colon that doesn't introduce a block, 
but only a tiny bit. There is precedent:

    lambda x, y: (x+y)/(x*y)


This suggests that perhaps the parentheses aren't needed unless you have
multiple except parts:

    things[i] (except IndexError, KeyError as exc: exc.args)
    things[i] except IndexError, KeyError as exc: exc.args


but I think they ought to be compulsory if you use multiple excepts. And 
of course they are useful for continuing over multiple lines.

I think this syntax looks good when used in compound expressions:

    mylist = [23, lambda x: x+1, things[i] except IndexError: 42, ""]

    result = function(a, b except NameError: "undefined", c)

    result = function(a, b, c) except ValueError: float('nan')

    if something(x) except TypeError: None:
        block


Dicts are problematic. Should the dict colon bind more or less strongly 
than the except colon? I suggest we follow the same rule as for lambda:

    adict = {lambda x: x+1: "value",
             key+1 except TypeError: 23: "value",
             }


Here is a torture-test for the syntax: can we combine it with an 
if-expression? I think we can, although you may need parentheses to 
disambiguate the expression:

    something(x) (except TypeError: a if condition else b)

    ((something(x) if x else other(x)) (except ValueError: -1)

    something(x) if x else (other(x) except ValueError: -1)


Trying to do too much in a single expression is never exactly 
*beautiful*, but it can be read.

This does look a tiny bit like a function call, especially if you delete 
the space between the leading expression and the opening bracket:

    # ugly, don't do this
    things[i](except IndexError: 42)

but that's not actually ambiguous, since the keyword except cannot be an 
argument to a function.

I like this. I think this is the first non-sucky syntax I've seen (sorry 
to everyone who proposed sucky syntax *wink*).


 
> This has the advantage of putting the colon inside parens,
> where it's less likely to get confused with other uses of
> colons in the same line (by humans, if not by the computer).
> 
> Also it might be useful to be able to say
> 
>    things.remove(i) (except ValueError: pass)
> 
> which would be equivalent to
> 
>    things.remove(i) (except ValueError: None)
> 
> but would read more smoothly in cases where you're not
> interested in the value of the expression.

Certainly not! pass implies that *no return result is generated at all*, 
which is not possible in Python. Returning None is the right thing to 
do.



-- 
Steven


More information about the Python-ideas mailing list