It’s a short, simple PEP from @pablogsal and me to make the parentheses around the tuple of exception classes in except expressions be optional.
try:
...
except Spam, Bacon:
...
We figure since parentheses aren’t necessary thanks to Python 2 compatibility no longer being a driving concern and other parts of the grammar drop parentheses where possible (e.g., x = 1, 2), it also made sense to drop the parentheses in this instance as well.
+1 from me. It removes a quirk that is no longer necessary and wasn’t easy to explain in the first place without delving into the awkward “except type, name:” syntax. Definitely worth the change.
While the simple form looks fine, adding the as clause IMO makes this a bad idea:
try:
...
except ExceptionA, ExceptionB, ExceptionC as e:
...
What does as e bind to? In the other contexts it is used (import, case, with, …) it only binds to the last expression, i.e. it binds tighter than ,.
Ofcourse, from an implementation perspective the choice is clear, but this reduces consistency with other syntax. Only here the as “operator” suddenly changes it’s priority relative to ,.
A good point, but those examples also don’t stack like except expressions do, e.g.,
with A:
with B:
...
isn’t the same as
try:
...
except A:
...
except B:
...
because of how those statements are simply different in terms of what clauses are allowed, how many you can have, etc. So the fact that try statements have the variance of the clauses that follow make it a different situation for me.
… It behaves the same way, except for the fact that it’s completely different…
My point here is about the relative parsing priority between as and ,. Yes, as is not a real operator, but it will still be read like this by many people, and I think allowing this notation is going to cause extra confusion.
I am not really sure what point you are making. Yes, these are different, but they still read similar. And it terms of exact parallels in terms of syntax, import statements are pretty close I would say.
I mean that the “any of these, as name” part works the same way that exceptions do: case list() | set() | dict() as collection: will match any of those types, and stick it in the name “collection”. It’s a difference of character, but it’s still providing a group of options followed by an “as”.
Maybe the parentheses can stay mandatory if there are multiple exceptions and ‘as’ is used? In other words, parentheses can be dropped only in the simple and obvious case.
If there is consensus on this I am particularly ok with changing the PEP to reflect that although my preference is to just allow to drop them everywhere.
I think except ExceptionA, ExceptionB, ExceptionC as e: without the parenthesis loses its ambiguity when you ask yourself what the alternative interpretation would be. It would be quite an evil language that chose to only define e if the exception was of type ExceptionC, forcing you to use try/except NameError in the except body.
For me, adding another conditional on when you need the brackets is worse than no change at all (especially when it’s compounded by the next few years of Python versions also being an extra transitional conditional) so I’d vote for removing all brackets or for no change but definitely not the halfway house.
I think this would be a reasonable addition to PEP 8 (recommending the use of parentheses when multiple exception types are caught and bound to a common name) for the reasons given (as refers to the entire tuple of matched types here, not just the last element), but I don’t think it’s necessary to keep the distinction in the compiler.
I welcome the PEP but I’m battled on the as e syntax and where it binds to.
When I read the following code
try:
...
except ExceptionA, ExceptionB, ExceptionC as e:
...
I naturally read that e binds to ExceptionC only. I think it is the comma the causes issues because its meaning is like an OR (like the case in the match statement).
The comma in the import and with statements instead bears a meaning of an AND and as consequence you need to replicate the as for every element of the statement. E.g.
import os as a, sys as b
with open("/tmp/a", "r") as a, open("/tmp/b", "r") as b:
...
So if we want to be consistent with the syntax, maybe we should be considering something like
which is more disruptive change than just dropping the parenthesis.
Said that I don’t have strong opinions about that, but the as e feels odd and out of place. Personally for readability I might keep using parenthesis in case I have multiple exceptions to catch and I need to bind one of them to a variable.
Actually not impossible; all it means is that combining two exceptions needs to return something that can be used in an except clause. So either it means that types.UnionType needs to become valid in an except clause (and equivalent to a tuple), or BaseException needs to create tuples from bitwise or (presumably in addition to being UnionType). Personally I don’t think it’s necessary, but it would be a potential way forward if the comma bothers people.
I also prefer to allow to drop them everywhere (except when splitting across lines, of course).
Nobody is forcing you to drop them if you don’t want to, and you can invent whatever style guides you like for the developers you do get to force. The language should be flexible enough to handle what the developer thinks is most readable.
FWIW, except ExceptionA, ExceptionB as e also looks too ambiguous and confusing for my taste. It’s almost as if I would expect except ExceptionA as a, ExceptionB as b instead.
I’m not sure it was a great idea to allow UnionTypes in isinstance() and issubclass() (it tends to be slower and more verbose, and makes the already-fuzzy distinction the typing system makes between types and runtime values even more confusing). So I’m also not a massive fan of the idea.
I agree. There are other cases where valid, minimal syntax may not be the most optimally readable syntax, and that’s fine. As long as you still can add parentheses for readability, I’m totally fine with not requiring them. Linters jobs are to encourage better readability, so they can add warnings for these cases.