[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