[Python-ideas] except expression

Jan Kaliszewski zuo at chopin.edu.pl
Mon Feb 17 15:25:26 CET 2014


17.02.2014 05:46, Steven D'Aprano wrote:

> On Mon, Feb 17, 2014 at 09:19:22AM +1100, Chris Angelico wrote:
>> On Mon, Feb 17, 2014 at 7:39 AM, Jan Kaliszewski <zuo at chopin.edu.pl> 
>> wrote:
>> > 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.
>>
>> Maybe not, but the only thing preventing that from parsing as a 
>> tuple
>> containing two tuples is the colon a bit further along. That might 
>> be
>> sufficient for the lexer (in the same way that, for instance, 
>> function
>> arguments can contain tuples), but I suspect it may be confusing for
>> humans.
>
> It's certainly confusing for me!
>
> I'm now strongly leaning towards following the lead of generator
> expressions, and requiring parens around an except-expression. Like 
> gen
> expressions, you can leave the parens out if they are already there:
>
>     it = (calc(x) for x in iterable)  # parentheses are mandatory
>     result = sum(calc(x) for x in iterable)  # but this is okay
>
> So if your except-expression stands alone, or is inside some other
> unbracketed expression, you need to bracket it:
>
>     value = (expr except Error: default)
>     mytuple = (1, 2, (expr except Error: default), 3)
>
>
> But if it's already directly surrounded by parentheses, say inside a
> function call with no other arguments, there is no need to double-up:
>
>     result = function(expr except Error: default)

Now, I am confused a bit.  First you cite a discussion about the
paren-after-except syntax variant (the one I proposed) but then
you discuss the syntax variant from the PEP draft by Chris.

Please note that these variants are different.  See below...

> I think that this will ensure that there is no visual ambiguity when 
> you
> chain except-expressions. Even if the parser/lexer can disambiguate 
> the
> expression, it risks being completely impenetrable to the human 
> reader.
> Take this case, where I'm labelling parts for ease of discussion:
>
>     # What does this do?
>     expr except SpamError: spam except EggsError: eggs
>     #^^^^^FIRST^^^^^^^^^^^^^^^^ ^^^^^^SECOND^^^^^^^^^^
>
> Does the SECOND except capture exceptions in the evaluation of "spam"
> only, or in the entire FIRST except? If this question doesn't make 
> sense
> to you, then please ponder these two examples:
>
>     ((expr except SpamError: spam) except EggsError: eggs)
>     (expr except SpamError: (spam except EggsError: eggs))
>
>
> Requiring parens should also avoid the subtle error of leaving out a
> comma when you have multiple except-clauses:
>
>     expr except SpamError: spam, except EggsError: eggs
>     #..........................^
>
> is a single expression that catches two exceptions, equivalent to:
>
>     try:
>         _ = expr
>     except SpamError:
>         _ = spam
>     except EggsError:
>         _ = eggs
>
>
> whereas leaving out the comma:
>
>     expr except SpamError: spam except EggsError: eggs
>
> is *two* except-expressions, equivalent to either this:
>
>     try:
>         try:
>             _ = expr
>         except SpamError:
>             _ = spam
>     except EggsError:
>         _ = eggs
>
>
> or this:
>
>     try:
>         _ = expr
>     except SpamError:
>         try:
>             _ = spam
>         except EggsError:
>             _ = eggs
>
>
> depending on how strongly the except binds.
>
> The with- and without-comma versions are very subtly different, and
> consequently a potential bug magnet, from a very subtle and 
> easy-to-make
> typo. By requiring parens, you can avoid that. The first version
> becomes:
>
>     (expr except SpamError: spam, except EggsError: eggs)
>
> and dropping the comma is a SyntaxError, while the second version
> becomes either:
>
>     ((expr except SpamError: spam) except EggsError: eggs)
>     (expr except SpamError: (spam except EggsError: eggs))
>
>
> depending on which semantics you want.

On the other hand the paren-after-except variant makes it
unambiguous:

     expr except (SpamError: spam, EggsError: eggs)

is clearly different from:

     expr except (SpamError: spam) except (EggsError: eggs)

...which is the same as:

     (expr except (SpamError: spam)) except (EggsError: eggs)

...as neither "(SpamError: spam)" nor "except (SpamError: spam)"
are valid expressions themselves.  But only "EXPRESSION except
(SpamError: spam)" taken as a whole makes up a valid expression.

Cheers.
*j



More information about the Python-ideas mailing list