Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PEP 758: Allow except and except* expressions without parentheses #4008

Merged
merged 5 commits into from
Oct 1, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions peps/pep-0790.rst
AA-Turner marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
PEP: 790
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
Title: Removing the parentheses requirement from ``except`` expressions
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
Author: Pablo Galindo <[email protected]>, Brett Cannon <[email protected]>
PEP-Delegate: TBD
Discussions-To: xxxx
Status: Draft
Type: Standards Track
Created: 30-Sep-2024
Python-Version: 3.14


Abstract
========

This PEP [1]_ proposes to allow unparenthesized ``except`` blocks in Python's exception handling syntax. 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.
pablogsal marked this conversation as resolved.
Show resolved Hide resolved


Motivation
==========

The current syntax for catching multiple exceptions requires parentheses in the ``except`` expression: ::

try:
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
...
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: ::

try:
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
...
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.


Rationale
=========

The decision to allow unparenthesized ``except`` blocks is based on the following considerations:

1. Simplicity: Removing the requirement for parentheses simplifies the syntax, making it more consistent with other parts of the language.

2. Readability: In cases where many exceptions are being caught, the removal of parentheses can improve readability by reducing visual clutter.

3. Consistency: This change makes the ``except`` clause more consistent with other parts of Python where unambiguous, comma-separated lists don't require parentheses.

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: ::

except_block[excepthandler_ty]:
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
| invalid_except_stmt_indent
| 'except' e=expressions t=['as' z=NAME { z }] ':' b=block {
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
| 'except' ':' b=block { _PyAST_ExceptHandler(NULL, NULL, b, EXTRA) }
| invalid_except_stmt
except_star_block[excepthandler_ty]:
| invalid_except_star_stmt_indent
| 'except' '*' e=expressions t=['as' z=NAME { z }] ':' b=block {
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
| invalid_except_star_stmt


This allows both the current parenthesized syntax and the new unparenthesized syntax: ::

try:
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
...
except (ExceptionA, ExceptionB): # Still valid
...
except ExceptionC, ExceptionD: # New syntax
...

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`` blocks will continue to work without modification. The new syntax is purely additive and does not break any existing code.
pablogsal marked this conversation as resolved.
Show resolved Hide resolved


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: ::

try:
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
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: ::

# These are equivalent:
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
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: ::

except (ValueError, TypeError), OSError:

This was rejected due to the potential for confusion and to maintain a clear distinction between the two styles.
pablogsal marked this conversation as resolved.
Show resolved Hide resolved

Footnotes
=========

.. [1] Originally named "Parenthetically Speaking, We Don't Need 'Em"
hugovk marked this conversation as resolved.
Show resolved Hide resolved

Copyright
=========

This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.
Loading