[Python-Dev] Why not make frames? [was: Alternative forms [was: PEP 463: Exception-catching expressions]]
TL;DR:
expr except (default if exc_expr)
expr (except default if exc_expr)
expr except (exc_expr: default)
expr (except exc_expr: default)
(1) Group the exceptions with the default they imply.
(2) inline-":" still needs () or [] or {}.
(3) Consider the expression inside a longer line.
(3a) Does the except expression need to be general, or would it work
if it were limited to a subclause of variable assignments?
(3b) What about comprehensions?
On Fri Mar 7 20:54:31 CET 2014, Chris Angelico wrote:
>On Sat, Mar 8, 2014 at 5:58 AM, Jim J. Jewett wrote:
>> (Thu Mar 6 23:26:47 CET 2014) Chris Angelico responded:
>>> On Fri, Mar 7, 2014 at 7:29 AM, Jim J. Jewett
>>> wrote:
[ note that "x if y" already occurs in multiple contexts, and
always evaluates y before x. ]
...
> I don't see except expressions as fundamentally more associated with
> if/else than with, say, an or chain, which works left to right.
I do, because of the skipping portion.
Short-circuiting operators, such as an "or" chain, never skip a clause
unless they are skipping *every* subsequent clause.
An "if" statement sometimes skips the (unlabeled in python) "then"
clause, but still processes the even-later "else" clause.
A "try" statement sometimes skips the remainder of the try suite but
still executes the later subordinate "except" and "finally" clauses.
Note that this only explains why I see "except" as more closely related
to "if" than to "or"; it isn't sufficient to justify going back to
execute the skipped clause later. That said, going back to a previous
location is a lot easier to excuse after an error handler than in
"regular" code.
> Analysis of the Python standard library suggests that the single-if
> situation is *by far* the most common, to the extent that it'd hardly
> impact the stdlib at all to add multiple except clauses to the
> proposal. Do you have a strong use-case for the more full syntax?
I do not.
I dislike the arbitrary restriction, and I worry that lifting it later
(while maintaining backwards compatibility) will result in a syntax
wart, but I do not have a compelling use case for that later relaxation.
>> and I strongly prefer that they [the parentheses] be internal
>> (which you fear looks too much like calling a function named except).
>> In that case, it is:
>> expr1 except (expr3 if expr2)
> I'm still not really seeing how this is better.
For one thing, it makes it clear that the "if" keyword may be messing
with the order of evaluation.
I don't claim that syntax is perfect. I do think it is less flawed
than the no-parentheses (or external parentheses) versions:
(expr1 except expr3 if expr2)
expr1 except expr3 if expr2
because the tigher parentheses correctly indicate that expr2 and expr3
should be considered as a (what-to-do-in-case-of-error) group, which
interacts (as a single unit) with the main expression.
I also think it is (very slighly) better than the
colon+internal-parentheses version:
expr1 except (expr2: expr3)
which in turn is far, far better than the colon versions with external
or missing parentheses:
(expr1 except expr2: expr3)
expr1 except expr2: expr3
because I cannot imagine reading an embedded version of either of those
without having to mentally re-parse at the colon. An example assuming
a precedence level that may not be what the PEP proposes:
if myfunc(5, expr1 except expr2: expr3, "label"):
for i in range(3, 3*max(data) except TypeError: 9, 3):
...
if myfunc(5, (expr1 except expr2: expr3), "label"):
for i in range(3, (3*max(data) except TypeError: 9), 3):
...
if myfunc(5, expr1 except (expr2: expr3), "label"):
for i in range(3, 3*max(data) except (TypeError: 9), 3):
...
if myfunc(5, expr1 except (expr2: expr3), "label"):
for i in range(3, 3*max(data) (except TypeError: 9), 3):
...
if myfunc(5, expr1 except (expr3 if expr3), "label"):
for i in range(3, 3*max(data) (except 9 if TypeError), 3):
...
if myfunc(5, expr1 except (expr3 if expr3), "label"):
for i in range(3, 3*max(data) except (9 if TypeError), 3):
myarg = expr1 except (expr3 if expr2)
if myfunc(5, myarg, "label"):
limit = 3*max(data) except (9 if TypeError)
for i in range(3, limit, 3):
Yes, I would prefer to create a variable naming those expressions,
but these are all still simple enough that I would expect to have
to read them. (I like constructions that get ugly just a bit faster
than they get hard to understand.) If I have to parse any of them,
the ones at the bottom are less difficult than the ones at the top.
> With the colon version, it looks very much like dict display,
which is good, since that is one of the acceptable uses of inline-colon.
> only with different brackets around it; in some fonts, that'll be
> very easily confused.
I've had more trouble with comm
[Python-Dev] Scope issues [was: Alternative forms [was: PEP 463: Exception-catching expressions]]
On Fri Mar 7 20:54:31 CET 2014, Chris Angelico wrote: > On Sat, Mar 8, 2014 at 5:58 AM, Jim J. Jewett wrote: >> (Thu Mar 6 23:26:47 CET 2014) Chris Angelico responded: >>> ...[as-capturing is] deferred until there's a non-closure means of >>> creating a sub-scope. >> The problem is that once it is deployed as leaking into the parent >> scope, backwards compatibility may force it to always leak into >> the parent scope. (You could document the leakage as a bug or as >> implementation-defined, but ... those choices are also sub-optimal.) > It'll never be deployed as leaking, for the same reason that the > current 'except' statement doesn't leak: I don't think that is the full extent of the problem. From Nick's description, this is a nasty enough corner case that there may be glitches no one notices in time. The PEP should therefore explicitly state that implementation details may force the deferral to be permanent, and that this is considered an acceptable trade-off. -jJ -- Sorry for the botched subject line on the last previous message. If there are still threading problems with my replies, please email me with details, so that I can try to resolve them. -jJ ___ Python-Dev mailing list [email protected] https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Why not make frames? [was: Alternative forms [was: PEP 463: Exception-catching expressions]]
On Mon, Mar 10, 2014 at 1:16 PM, Jim J. Jewett wrote: > On Fri Mar 7 20:54:31 CET 2014, Chris Angelico wrote: >> I don't see except expressions as fundamentally more associated with >> if/else than with, say, an or chain, which works left to right. > > I do, because of the skipping portion. > > Short-circuiting operators, such as an "or" chain, never skip a clause > unless they are skipping *every* subsequent clause. > > An "if" statement sometimes skips the (unlabeled in python) "then" > clause, but still processes the even-later "else" clause. > > A "try" statement sometimes skips the remainder of the try suite but > still executes the later subordinate "except" and "finally" clauses. > > Note that this only explains why I see "except" as more closely related > to "if" than to "or"; it isn't sufficient to justify going back to > execute the skipped clause later. That said, going back to a previous > location is a lot easier to excuse after an error handler than in > "regular" code. This is a rather tenuous connection, I think. It also doesn't justify a fundamentally out-of-order evaluation. Compare all of these, which are - unless I've made a mistake somewhere - evaluated in the order shown (that is, no lower-numbered will be evaluated after a higher-numbered, but of course not everything will be evaluated): if expr1: stmt2 elif expr3: stmt4 else: stmt5 try: stmt1 except expr2: stmt3 except expr4: stmt5 except: stmt6 else: stmt7 finally: stmt8 value = expr1 or expr2 or expr3 or expr4 value = expr1 and expr2 and expr3 and expr4 # With the current recommendations in PEP 463 value = (expr1 except expr2: expr3) value = expr2 if expr1 else expr3 The if expression is the *only* one that's out of order, and it's justified by (a) "reading" correctly (ie being similar to English), and (b) using two existing keywords, rather than creating a 'then' keyword or using symbols. Useful reading: http://legacy.python.org/dev/peps/pep-0308/ Skip down to the "Detailed Results of Voting" section (sorry, text/plain PEPs don't do hash links) and note that these four proposals received the most support: A. x if C else y B. if C then x else y C. (if C: x else: y) D. C ? x : y with more support for C and D than for A and B. B requires a new keyword, D is all symbols, C is indistinguishable from the statement without the parens, and A puts the expressions in the wrong order. All of them are somewhat flawed but all of them have some merit, too. The BDFL went for A (which proves that Python isn't a democracy), and there's no explanation of the reasoning behind that, but in the absence of a strong statement on the subject, I would say that the gap between the above four options is sufficiently narrow that this can't be used to justify out-of-order syntax in any other proposal. >> Analysis of the Python standard library suggests that the single-if >> situation is *by far* the most common, to the extent that it'd hardly >> impact the stdlib at all to add multiple except clauses to the >> proposal. Do you have a strong use-case for the more full syntax? > > I do not. > > I dislike the arbitrary restriction, and I worry that lifting it later > (while maintaining backwards compatibility) will result in a syntax > wart, but I do not have a compelling use case for that later relaxation. That's one reason for the mandatory external parentheses. With some real-world usage data from Python 3.5, if this were implemented exactly per the PEP, a decision could be made in 3.6 to lift one of two restrictions: 3.5: (expr1 except Exception2: expr3) 3.6 choice 1: expr1 except Exception2: expr3 3.6 choice 2: (expr1 except Exception2: expr3 except Exception4: expr5) But these are incompatible. Lifting either restriction mandates the retention of the other. Note also that internal parens are less easily removed - it becomes two distinct code branches. Removing the requirement to have external parents simply means that old-style code is putting parens around an expression, no different from: value = (1 if x else 2) value = (3 + 5) and completely harmless. Allowing optional internal parens means maintaining two syntaxes forever, and both human and computer parsers would have to be compatible with both. >>> and I strongly prefer that they [the parentheses] be internal >>> (which you fear looks too much like calling a function named except). >>> In that case, it is: > >>> expr1 except (expr3 if expr2) > >> I'm still not really seeing how this is better. > > For one thing, it makes it clear that the "if" keyword may be messing > with the order of evaluation. It still could be waiting for its else. I mean, it's bad code style, but you theoretically could do this: foo[x] except (IndexError if isinstance(foo,list) else KeyError): None Really bad style and horribly unclear (and anyway, you could just catch LookupError), but grammatically legal. Anything using the word 'if' in an
Re: [Python-Dev] Scope issues [was: Alternative forms [was: PEP 463: Exception-catching expressions]]
On Mon, Mar 10, 2014 at 1:35 PM, Jim J. Jewett wrote: > The PEP should therefore explicitly state that implementation details > may force the deferral to be permanent, and that this is considered an > acceptable trade-off. How about words to this effect? """Should there be, in future, a way to create a true subscope (which could simplify comprehensions, except expressions, with blocks, and possibly more), then this proposal could be revived; until then, its loss is not a great one...""" (I parked the time machine in the PSU's garage, thanks for lending me it!) (The PSU does not exist, and therefore does not have a garage.) ChrisA ___ Python-Dev mailing list [email protected] https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
