[Python-ideas] except expression

Jan Kaliszewski zuo at chopin.edu.pl
Sun Feb 16 21:39:04 CET 2014


16.02.2014 14:01, Chris Angelico wrote:

> On Sun, Feb 16, 2014 at 11:01 PM, Jan Kaliszewski <zuo at chopin.edu.pl> 
> wrote:
>> In terms of my proposal it would clearly be just:
>>
>>     expr except (Exception1: default1) except (Exception2: default2)
>>
>> Of course grouping parens could be added without changing semantics:
>>
>>     (expr except (Exception1: default1)) except (Exception2: 
>> default2)
>>
>> Also, see below...
>
> Actually that _does_ change semantics, but in an extremely subtle 
> way.

As log as we are talking about my proposal -- it does not.  The 
proposed
syntax is roughly:

     <EXPR #0> except (<EXCEPTION SPEC #1> [as <VAR #1>]: <EXPR #1>, 
...)

...and all these elements make up a compound expression (which 
obviously
can be used as <EXPR #0> or <EXPR #1> in another except-compound-expr).

> In both versions, expr raising Exception2 will result in default2; 
> but
> the first version is effectively this:
>
> try:
>     _ = expr
> except Exception1:
>     _ = default1
> except Exception2:
>     _ = default2
> value_of_expression = _
>
> If the evaluation of default1 raises Exception2, then this form will
> propagate that exception up. The second form is actually like this:
>
> try:
>     try:
>         _ = expr
>     except Exception1:
>         _ = default1
> except Exception2:
>     _ = default2
> value_of_expression = _

No, both expression forms I mentioned are equivalent to the *latter*
(the nested one) of the above snippets.

Equivalent to the *former* (the "flat" one) of the above snippets
would be just the expression:

     expr except (Exception1: default1,
                  Exception2: default2)

[snip]
>> Before I posted the proposal I did think about the "things[i] 
>> (except
>> ..." variant also but I don't like that the opening parenthesis
>> character suggest to a human reader that it is a call...  On the 
>> other
>> hand, when the parenthesis is *after* the 'except' keyword it is 
>> clear
>> for human readers that it is a dedicated syntax having nothing to do
>> with a call.
>
> I don't see it as particularly significant either way. Opening parens
> and immediately having a keyword like "except" is strongly indicative
> of something different going on; same goes for having that keyword
> just _before_ the parens.

Apparently it's a subjective matter as I feel that "expr except (...)"
is less misleading for human eyes...

>> ...and/or:
>>
>>     # with multiple exception catches
>>     some_io() except (FileNotFoundError: 42,
>>                       OSError as exc: exc.errno)
>>
>> Also, for a multiple-exception-catches-variant I don't like 
>> repeating
>> the 'except' keyword for each catch, as well as the ambiguity 
>> whether
>> the consecutive 'except...' concerns only the initial expression or
>> also the preceding 'except...').  In my proposal there is no such
>> ambiguity.
>
> There's an ambiguity in this version, though. After the 'except'
> keyword, you can have a tuple of exceptions:
>
> try:
>     1/x
> except (NameError, ZeroDivisionError):
>     print("Can't divide by nothing!")
>
> If the previous value is followed by a comma and the next thing could
> be a tuple, the parsing is going to get a bit hairy. Either the
> previous value or the exception_list could be a tuple. I'd rather
> repeat the word 'except'.

Sorry, I don't catch the point.  If I needed to use a complex
exception spec (a tuple-like) and/or a tuple as the "default"
expression -- I'd just do it:

     some_io() except (FileNotFoundError: (1, 2, 3),
                       (ValueError, TypeError): 'spam')

I see no ambiguity here.

> I'm happy with them being optional in cases where it's unambiguous,
> but I'd be okay with mandating them to disambiguate. After all, if 
> the
> language says they're optional, style guides have the option of
> mandating; but if the language mandates, the freedom is gone.

Sometimes -- in syntax -- freedom is a bad thing.  There are good
reasons that 1-argument function calls have the form: "func(arg)" and
not "func arg" -- though the latter could still be unambiguous.

>> More complex (though probably not very realistic) example:
>>
>>     msg = (cache[k] except (
>>                LookupError: backend.read() except (
>>                    OSError: 'resource not available'))
>>            if check_permission(k)
>>            else 'access not allowed'
>>           ) except (Exception: 'internal error occurred')
>
> Fairly unrealistic, as the backend.read() call won't get put into the

The example was about syntax of nested expressions, not about this or
that use case.

> cache (and you can't put the final msg into the cache, as 'resource
> not available' sounds temporary and thus non-cached), not to mention
> that swallowing Exception to just return a constant string seems like
> a really REALLY bad idea! :) But this highlights another big issue:
> How should a complex except expression be laid out? With the 
> statement
> form, it's pretty clear: first you do the line(s) that you're trying,
> then you have your except clauses, no more than one on any given 
> line,
> and then you have your else, and your finally, if you have either.
> Everything's on separate lines. What about here? If it all fits on 
> one
> line, great! But it often won't (the name "ZeroDivisionError" is over
> a fifth of your typical line width, all on its own), and then where 
> do
> you break it? Not technically part of the proposal, but it's going to
> be an issue.

If we talk about *one* complex except expression, in terms of the
syntax variant I proposed, the natural layout form seems to be:

     <EXPR #0> except (<EXCEPTION SPEC #1> [as VAR #1]: <EXPR #1>,
                       <EXCEPTION SPEC #2> [as VAR #3]: <EXPR #2>,
                       <EXCEPTION SPEC #3> [as VAR #3]: <EXPR #3>)

or

     <EXPR #0> except (
         <EXCEPTION SPEC #1> [as VAR #1]: <EXPR #1>,
         <EXCEPTION SPEC #2> [as VAR #3]: <EXPR #2>,
         <EXCEPTION SPEC #3> [as VAR #3]: <EXPR #3>)

Cheers.
*j



More information about the Python-ideas mailing list