Skip to main content
The except* clause is a control flow mechanism introduced in Python 3.11 designed to handle ExceptionGroup and BaseExceptionGroup objects. Unlike the traditional except clause, which catches and handles a single exception, except* performs type-based matching and extraction on an exception tree, allowing multiple except* blocks to execute sequentially if their specified exception types are present within the group.

Core Mechanics

Exception Splitting When an exception group is raised, the Python interpreter evaluates it against the except* clauses. If a clause matches one or more exceptions within the group, the interpreter “splits” the group. The matched exceptions are extracted and passed into the except* block, while the unmatched exceptions are retained in a new exception group to be evaluated by subsequent except* clauses. Multiple Executions Because of the splitting mechanism, multiple except* clauses attached to a single try block can execute during a single exception handling phase. This is a fundamental departure from standard except clauses, where execution halts after the first matching block. Alias Binding The object bound to the target alias (e.g., as e) is never a direct instance of the matched exception. Instead, it is an exception group (ExceptionGroup or BaseExceptionGroup, depending on whether the matched exceptions include a BaseException that is not an Exception). This new group contains only the exceptions from the original group that matched the clause’s type, preserving the original nesting structure. Implicit Re-raising If the original group contains exceptions that do not match any of the provided except* clauses, those remaining exceptions are automatically re-raised after all except* blocks have been evaluated. They are re-raised as an ExceptionGroup, or as a BaseExceptionGroup if any of the unmatched exceptions inherit directly from BaseException (e.g., KeyboardInterrupt).

Control Flow Interruptions

The except* clause introduces unique control flow mechanics when execution is interrupted from inside the block:
  • Raising Exceptions: If a new exception is raised inside an except* block, it does not immediately propagate and halt the evaluation of the original exception group. Instead, the newly raised exception is suspended. Subsequent except* clauses continue to evaluate the remaining unmatched exceptions. Once all clauses are evaluated, all suspended exceptions raised from within the except* blocks are combined with any remaining unmatched exceptions from the original group and raised together as a new exception group.
  • return, break, and continue: If an except* block executes a return, break, or continue statement, the exception handling phase is immediately aborted. Subsequent except* clauses are skipped, and any remaining unmatched exceptions from the original group are silently dropped.

Syntax Rules and Constraints

  • Mutual Exclusivity: You cannot mix except and except* clauses on the same try block. A try block must use exclusively one or the other.
  • Subclass Matching: Like standard except, except* respects the class hierarchy. except* OSError: will match and extract FileNotFoundError, PermissionError, and any other OSError subclasses present in the group.
  • Naked Exceptions: If a standard, single exception (a “naked” exception, not an exception group) is raised inside a try block monitored by except*, it is evaluated against the clauses. If it matches an except* clause, it is dynamically wrapped in an exception group (ExceptionGroup, or BaseExceptionGroup if it is a BaseException like SystemExit) strictly for the purpose of binding to the alias. If the naked exception does not match any except* clause, it propagates outward as the original naked exception, not as an exception group.
  • Catching the Group: You cannot use except* ExceptionGroup: or except* BaseExceptionGroup:. The except* syntax is designed to match the types of the exceptions contained within the group, not the group container itself. To catch all exceptions within a group, you must use except* Exception: or except* BaseException:.
Tired of Poor Python Skills? Fix That With Deep Grasping!Learn More