[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