TypeError
   ... except:
   ...     print(repr(sys.exception()))
   ...     try:
   ...          raise ValueError
   ...     except:
   ...         print(repr(sys.exception()))
   ...     print(repr(sys.exception()))
   ...
   TypeError()
   ValueError()
   TypeError()
   >>> print(sys.exception())
   None


"except*" clause
================

The "except*" clause(s) are used for handling "ExceptionGroup"s. The
exception type for matching is interpreted as in the case of "except",
but in the case of exception groups we can have partial matches when
the type matches some of the exceptions in the group. This means that
multiple "except*" clauses can execute, each handling part of the
exception group. Each clause executes at most once and handles an
exception group of all matching exceptions.  Each exception in the
group is handled by at most one "except*" clause, the first that
matches it.

   >>> try:
   ...     raise ExceptionGroup("eg",
   ...         [ValueError(1), TypeError(2), OSError(3), OSError(4)])
   ... except* TypeError as e:
   ...     print(f'caught {type(e)} with nested {e.exceptions}')
   ... except* OSError as e:
   ...     print(f'caught {type(e)} with nested {e.exceptions}')
   ...
   caught <class 'ExceptionGroup'> with nested (TypeError(2),)
   caught <class 'ExceptionGroup'> with nested (OSError(3), OSError(4))
     + Exception Group Traceback (most recent call last):
     |   File "<stdin>", line 2, in <module>
     | ExceptionGroup: eg
     +-+---------------- 1 ----------------
       | ValueError: 1
       +------------------------------------

Any remaining exceptions that were not handled by any "except*" clause
are re-raised at the end, along with all exceptions that were raised
from within the "except*" clauses. If this list contains more than one
exception to reraise, they are combined into an exception group.

If the raised exception is not an exception group and its type matches
one of the "except*" clauses, it is caught and wrapped by an exception
group with an empty message string.

   >>> try:
   ...     raise BlockingIOError
   ... except* BlockingIOError as e:
   ...     print(repr(e))
   ...
   ExceptionGroup('', (BlockingIOError()))

An "except*" clause must have a matching expression; it cannot be
"except*:". Furthermore, this expression cannot contain exception
group types, because that would have ambiguous semantics.

It is not possible to mix "except" and "except*" in the same "try".
The "break", "continue", and "return" statements cannot appear in an
"except*" clause.


"else" clause
=============

The optional "else" clause is executed if the control flow leaves the
"try" suite, no exception was raised, and no "return", "continue", or
"break" statement was executed.  Exceptions in the "else" clause are
not handled by the preceding "except" clauses.


"finally" clause
================

If "finally" is present, it specifies a ‘cleanup’ handler.  The "try"
clause is executed, including any "except" and "else" clauses.  If an
exception occurs in any of the clauses and is not handled, the
exception is temporarily saved. The "finally" clause is executed.  If
there is a saved exception it is re-raised at the end of the "finally"
clause.  If the "finally" clause raises another exception, the saved
exception is set as the context of the new exception. If the "finally"
clause executes a "return", "break" or "continue" statement, the saved
exception is discarded:

   >>> def f():
   ...     try:
   ...         1/0
   ...     finally:
   ...         return 42
   ...
   >>> f()
   42

The exception information is not available to the program during
execution of the "finally" clause.

When a "return", "break" or "continue" statement is executed in the
"try" suite of a "try"…"finally" statement, the "finally" clause is
also executed ‘on the way out.’

The return value of a function is determined by the last "return"
statement executed.  Since the "finally" clause always executes, a
"return" statement executed in the "finally" clause will always be the
last one executed:

   >>> def foo():
   ...     try:
   ...         return 'try'
   ...     finally:
   ...         return 'finally'
   ...
   >>> foo()
   'finally'

Changed in version 3.8: Prior to Python 3.8, a "continue" statement
was illegal in the "finally" clause due to a problem with the
implementation.
uF