2024-10-01 17:55:14 -04:00
|
|
|
|
PEP: 758
|
|
|
|
|
Title: Allow ``except`` and ``except*`` expressions without parentheses
|
|
|
|
|
Author: Pablo Galindo <pablogsal@python.org>, Brett Cannon <brett@python.org>
|
|
|
|
|
PEP-Delegate: TBD
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Created: 30-Sep-2024
|
|
|
|
|
Python-Version: 3.14
|
2024-10-02 19:11:48 -04:00
|
|
|
|
Post-History: `02-Oct-2024 <https://discuss.python.org/t/66453>`__
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
This PEP [1]_ proposes to allow unparenthesized ``except`` and ``except*``
|
2024-10-19 15:41:51 -04:00
|
|
|
|
blocks in Python's exception handling syntax only when not using the ``as``
|
|
|
|
|
clause. Currently, when catching multiple exceptions, parentheses are required
|
|
|
|
|
around the exception types. This was a Python 2 remnant. This PEP suggests allowing
|
|
|
|
|
the omission of these parentheses, simplifying the syntax, making it more consistent
|
|
|
|
|
with other parts of the syntax that make parentheses optional, and improving readability
|
|
|
|
|
in certain cases.
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
|
|
|
|
Motivation
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
The current syntax for catching multiple exceptions requires parentheses in the
|
|
|
|
|
``except`` expression (equivalently for the ``except*`` expression). For
|
|
|
|
|
example:
|
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
...
|
|
|
|
|
except (ExceptionA, ExceptionB, ExceptionC):
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
While this syntax is clear and unambiguous, it can be seen as unnecessarily
|
|
|
|
|
verbose in some cases, especially when catching a large number of exceptions. By
|
|
|
|
|
allowing the omission of parentheses, we can simplify the syntax:
|
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
...
|
|
|
|
|
except ExceptionA, ExceptionB, ExceptionC:
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
This change would bring the syntax more in line with other comma-separated lists
|
|
|
|
|
in Python, such as function arguments, generator expressions inside of a
|
|
|
|
|
function call, and tuple literals, where parentheses are optional.
|
|
|
|
|
|
|
|
|
|
The same change would apply to ``except*`` expressions. For example:
|
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
...
|
|
|
|
|
except* ExceptionA, ExceptionB, ExceptionC:
|
|
|
|
|
...
|
|
|
|
|
|
2024-10-19 15:41:51 -04:00
|
|
|
|
When using the ``as`` clause to capture the exception instance paretheses must
|
|
|
|
|
be used as before. Some users have expressed that they would find it confusing not
|
|
|
|
|
to require parentheses as it would be unclear what exactly is being assigned to
|
|
|
|
|
the target since in other parts of the language multiple ``as`` clauses can be used
|
|
|
|
|
in similar situations (like in imports and context managers). This means that if
|
|
|
|
|
an ``as`` clause its being added to the previous example it must be done as:
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
...
|
2024-10-19 15:41:51 -04:00
|
|
|
|
except (ExceptionA, ExceptionB, ExceptionC) as e:
|
2024-10-01 17:55:14 -04:00
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
The decision to allow unparenthesized ``except`` blocks is based on the
|
|
|
|
|
following considerations:
|
|
|
|
|
|
|
|
|
|
1. Simplicity: Removing the requirement for parentheses simplifies the syntax,
|
2024-10-01 18:47:21 -04:00
|
|
|
|
making it more consistent with other parts of the language.
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
|
|
|
|
2. Readability: In cases where many exceptions are being caught, the removal of
|
2024-10-01 18:47:21 -04:00
|
|
|
|
parentheses can improve readability by reducing visual clutter.
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
2024-10-01 18:47:21 -04:00
|
|
|
|
3. Consistency: This change makes the ``except`` clause more consistent with
|
|
|
|
|
other parts of Python where unambiguous, comma-separated lists don't require
|
|
|
|
|
parentheses.
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
The syntax for the except clause will be modified to allow an unparenthesized
|
|
|
|
|
list of exception types. The grammar will be updated as follows:
|
|
|
|
|
|
|
|
|
|
.. code-block:: peg
|
|
|
|
|
|
2024-10-01 18:47:21 -04:00
|
|
|
|
except_block:
|
2024-10-19 15:41:51 -04:00
|
|
|
|
| 'except' expressions ':' block
|
|
|
|
|
| 'except' expression 'as' NAME ':' block
|
2024-10-01 18:47:21 -04:00
|
|
|
|
| 'except' ':' block
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
2024-10-01 18:47:21 -04:00
|
|
|
|
except_star_block
|
2024-10-19 15:41:51 -04:00
|
|
|
|
| 'except' '*' expressions ':' block
|
|
|
|
|
| 'except' '*' expression 'as' NAME ':' block
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
|
|
|
|
This allows both the current parenthesized syntax and the new unparenthesized
|
2024-10-19 15:41:51 -04:00
|
|
|
|
syntax while requiring parentheses when the ``as`` keyword is used:
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
...
|
|
|
|
|
except (ExceptionA, ExceptionB): # Still valid
|
|
|
|
|
...
|
|
|
|
|
except ExceptionC, ExceptionD: # New syntax
|
|
|
|
|
...
|
2024-10-19 15:41:51 -04:00
|
|
|
|
except (ExceptionE, ExceptionF) as e: # Parentheses still required
|
|
|
|
|
...
|
2024-10-01 17:55:14 -04:00
|
|
|
|
|
|
|
|
|
The semantics of exception handling remain unchanged. The interpreter will catch
|
|
|
|
|
any of the listed exceptions, regardless of whether they are parenthesized or
|
|
|
|
|
not.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Backwards Compatibility
|
|
|
|
|
=======================
|
|
|
|
|
|
|
|
|
|
This change is fully backwards compatible. All existing code using parenthesized
|
|
|
|
|
``except`` and ``except*`` blocks will continue to work without modification.
|
|
|
|
|
The new syntax is purely additive and does not break any existing code.
|
|
|
|
|
|
|
|
|
|
It's worth noting that in Python 2 the unparenthesized syntax was allowed with
|
|
|
|
|
two elements, but had different semantics, in which the first element of the
|
|
|
|
|
list was used as the exception type and the second element as the capture
|
|
|
|
|
variable. This change does not reintroduce the Python 2 semantics, and the
|
|
|
|
|
unparenthesized syntax will behave identically to the parenthesized version.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Security Implications
|
|
|
|
|
=====================
|
|
|
|
|
|
|
|
|
|
There are no known security implications for this change. The semantics of
|
|
|
|
|
exception handling remain the same, and this is purely a syntactic change.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
How to Teach This
|
|
|
|
|
=================
|
|
|
|
|
|
|
|
|
|
For new Python users, the unparenthesized syntax can be taught as the standard
|
|
|
|
|
way to catch multiple exceptions:
|
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
risky_operation()
|
|
|
|
|
except ValueError, TypeError, OSError:
|
|
|
|
|
handle_errors()
|
|
|
|
|
|
|
|
|
|
For experienced users, it can be introduced as a new, optional syntax that can
|
|
|
|
|
be used interchangeably with the parenthesized version. Documentation should
|
|
|
|
|
note that both forms are equivalent:
|
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
|
|
# These are equivalent:
|
|
|
|
|
except (ValueError, TypeError):
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
except ValueError, TypeError:
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
It should be emphasized that this is purely a syntactic change and does not
|
|
|
|
|
affect the behaviour of exception handling.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Reference Implementation
|
|
|
|
|
========================
|
|
|
|
|
|
|
|
|
|
A proof-of-concept implementation is available at
|
|
|
|
|
https://github.com/pablogsal/cpython/commits/notuples/. This implementation
|
|
|
|
|
modifies the Python parser to accept the new syntax and ensures that it behaves
|
|
|
|
|
identically to the parenthesized version.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rejected Ideas
|
|
|
|
|
==============
|
|
|
|
|
|
|
|
|
|
1. Allowing mixed parenthesized and unparenthesized syntax:
|
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
...
|
|
|
|
|
except (ValueError, TypeError), OSError:
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
This was rejected due to the potential for confusion and to maintain a clear
|
|
|
|
|
distinction between the two styles.
|
|
|
|
|
|
2024-10-19 15:41:51 -04:00
|
|
|
|
Deferred Ideas
|
|
|
|
|
==============
|
|
|
|
|
|
|
|
|
|
1. Allowing unparenthesized expressions when the ``as`` keyword is used. The reason
|
|
|
|
|
we have decided to defer this particular form given that there isn't clear
|
|
|
|
|
consensus either way and there are reasonable arguments for both positions, the safest
|
|
|
|
|
approach is keeping the parentheses requirement since it can be removed later if users
|
|
|
|
|
find the disconnect too acute, while taking it out and users deciding it was a bad idea
|
|
|
|
|
doesn’t make it easy to put back.
|
|
|
|
|
|
2024-10-01 17:55:14 -04:00
|
|
|
|
Footnotes
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
.. [1] Originally named "Parenthetically Speaking, We Don't Need 'Em"
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document is placed in the public domain or under the
|
|
|
|
|
CC0-1.0-Universal license, whichever is more permissive.
|