Skip to content
This repository was archived by the owner on Apr 10, 2022. It is now read-only.

Commit f5da6d1

Browse files
committed
Prohibit returning from except*
1 parent c04f7f3 commit f5da6d1

File tree

1 file changed

+19
-62
lines changed

1 file changed

+19
-62
lines changed

except_star.md

Lines changed: 19 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -399,79 +399,36 @@ except *TypeError as e:
399399
# )
400400
```
401401

402-
### "continue" and "break" in "except*"
402+
### "continue", "break", and "return" in "except*"
403403

404-
Both `continue` and `break` are disallowed in `except*` clauses, causing
405-
a `SyntaxError`.
404+
`continue`, `break`, and `return` are disallowed in `except*` clauses,
405+
causing a `SyntaxError`.
406406

407-
Due to the fact that `try..except*` block allows multiple `except*` clauses
408-
to run while handling one `ExceptionGroup` with multiple different exceptions
409-
in it, allowing one innocent `break` or `continue` in one `except*` to
410-
effectively silence the entire group feels very error prone.
411-
412-
### "return" in "except*"
413-
414-
A `return` in a regular `except` or `finally` clause means
415-
"suppress the exception". For example, both of the below functions would
416-
silence their `ZeroDivisionError`s:
407+
Consider if they were allowed:
417408

418409
```python
419410
def foo():
420-
try:
421-
1 / 0
422-
finally:
423-
print('the sound of')
424-
return
425-
426-
def bar():
427-
try:
428-
1 / 0
429-
except ZeroDivisionError:
430-
return
431-
finally:
432-
print('silence')
433-
434-
foo()
435-
bar()
436-
437-
# would print:
438-
#
439-
# the sound of
440-
# silence
441-
```
442-
443-
We propose to replicate this behavior in the `except*` syntax as it is useful
444-
as an escape hatch when it's clear that all exceptions can be silenced.
445-
446-
That said, the regular try statement allows to return a value from the except
447-
or the finally clause:
448-
449-
```python
450-
def bar():
451-
try:
452-
1 / 0
453-
except ZeroDivisionError:
454-
return 42
455-
456-
print(bar())
457-
458-
# would print "42"
459-
```
460-
461-
Allowing non-None returns in `except*` allows to write unpredictable code,
462-
e.g.:
463-
464-
```python
465-
try:
411+
try:
466412
raise ExceptionGroup(A(), B())
467-
except *A:
413+
except *A:
468414
return 1
469-
except *B:
415+
except *B:
470416
return 2
417+
418+
print(foo())
471419
```
472420

473-
Therefore non-None returns are disallowed in `except*` clauses.
421+
In the above example the user could guess that most likely the program
422+
would print "1". But if instead of a simple `raise ExceptionGroup(A(), B())`
423+
there's scheduling of a few concurrent tasks the answer is no longer obvious.
424+
425+
Ultimately though, due to the fact that `try..except*` block allows multiple
426+
`except*` clauses to run while handling one `ExceptionGroup` with
427+
multiple different exceptions in it, allowing one innocent `break`, `continue`,
428+
or `return` in one `except*` to effectively silence the entire group of
429+
errors is error prone.
474430

431+
We can consider allowing some of them in future versions of Python.
475432

476433
## Design Considerations
477434

0 commit comments

Comments
 (0)