diff options
author | Irit Katriel <1055913+iritkatriel@users.noreply.github.com> | 2022-04-13 20:45:33 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-13 20:45:33 (GMT) |
commit | 04f9658c591f61f0d45ab1a818840a4c4ef82f64 (patch) | |
tree | 42cdce4742895dd4ba0dd5aad043b1934fcb689e | |
parent | 3fc57e8f6ff925b561b03c46bcf5bd323782c19c (diff) | |
download | cpython-04f9658c591f61f0d45ab1a818840a4c4ef82f64.zip cpython-04f9658c591f61f0d45ab1a818840a4c4ef82f64.tar.gz cpython-04f9658c591f61f0d45ab1a818840a4c4ef82f64.tar.bz2 |
gh-90449: Improve accuracy and readability of exceptions tutorial (GH-31899)
-rw-r--r-- | Doc/tutorial/errors.rst | 100 |
1 files changed, 54 insertions, 46 deletions
diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 888740c..01fd762 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -147,10 +147,52 @@ For example, the following code will print B, C, D in that order:: Note that if the *except clauses* were reversed (with ``except B`` first), it would have printed B, B, B --- the first matching *except clause* is triggered. -All exceptions inherit from :exc:`BaseException`, and so it can be used to serve -as a wildcard. Use this with extreme caution, since it is easy to mask a real -programming error in this way! It can also be used to print an error message and -then re-raise the exception (allowing a caller to handle the exception as well):: +When an exception occurs, it may have associated values, also known as the +exception's *arguments*. The presence and types of the arguments depend on the +exception type. + +The *except clause* may specify a variable after the exception name. The +variable is bound to the exception instance which typically has an ``args`` +attribute that stores the arguments. For convenience, builtin exception +types define :meth:`__str__` to print all the arguments without explicitly +accessing ``.args``. :: + + >>> try: + ... raise Exception('spam', 'eggs') + ... except Exception as inst: + ... print(type(inst)) # the exception instance + ... print(inst.args) # arguments stored in .args + ... print(inst) # __str__ allows args to be printed directly, + ... # but may be overridden in exception subclasses + ... x, y = inst.args # unpack args + ... print('x =', x) + ... print('y =', y) + ... + <class 'Exception'> + ('spam', 'eggs') + ('spam', 'eggs') + x = spam + y = eggs + +The exception's :meth:`__str__` output is printed as the last part ('detail') +of the message for unhandled exceptions. + +:exc:`BaseException` is the common base class of all exceptions. One of its +subclasses, :exc:`Exception`, is the base class of all the non-fatal exceptions. +Exceptions which are not subclasses of :exc:`Exception` are not typically +handled, because they are used to indicate that the program should terminate. +They include :exc:`SystemExit` which is raised by :meth:`sys.exit` and +:exc:`KeyboardInterrupt` which is raised when a user wishes to interrupt +the program. + +:exc:`Exception` can be used as a wildcard that catches (almost) everything. +However, it is good practice to be as specific as possible with the types +of exceptions that we intend to handle, and to allow any unexpected +exceptions to propagate on. + +The most common pattern for handling :exc:`Exception` is to print or log +the exception and then re-raise it (allowing a caller to handle the +exception as well):: import sys @@ -159,16 +201,13 @@ then re-raise the exception (allowing a caller to handle the exception as well): s = f.readline() i = int(s.strip()) except OSError as err: - print("OS error: {0}".format(err)) + print("OS error:", err) except ValueError: print("Could not convert data to an integer.") - except BaseException as err: + except Exception as err: print(f"Unexpected {err=}, {type(err)=}") raise -Alternatively the last except clause may omit the exception name(s), however the exception -value must then be retrieved with ``sys.exception()``. - The :keyword:`try` ... :keyword:`except` statement has an optional *else clause*, which, when present, must follow all *except clauses*. It is useful for code that must be executed if the *try clause* does not raise an exception. @@ -188,39 +227,8 @@ the :keyword:`try` clause because it avoids accidentally catching an exception that wasn't raised by the code being protected by the :keyword:`!try` ... :keyword:`!except` statement. -When an exception occurs, it may have an associated value, also known as the -exception's *argument*. The presence and type of the argument depend on the -exception type. - -The *except clause* may specify a variable after the exception name. The -variable is bound to an exception instance with the arguments stored in -``instance.args``. For convenience, the exception instance defines -:meth:`__str__` so the arguments can be printed directly without having to -reference ``.args``. One may also instantiate an exception first before -raising it and add any attributes to it as desired. :: - - >>> try: - ... raise Exception('spam', 'eggs') - ... except Exception as inst: - ... print(type(inst)) # the exception instance - ... print(inst.args) # arguments stored in .args - ... print(inst) # __str__ allows args to be printed directly, - ... # but may be overridden in exception subclasses - ... x, y = inst.args # unpack args - ... print('x =', x) - ... print('y =', y) - ... - <class 'Exception'> - ('spam', 'eggs') - ('spam', 'eggs') - x = spam - y = eggs - -If an exception has arguments, they are printed as the last part ('detail') of -the message for unhandled exceptions. - -Exception handlers don't just handle exceptions if they occur immediately in the -*try clause*, but also if they occur inside functions that are called (even +Exception handlers do not handle only exceptions that occur immediately in the +*try clause*, but also those that occur inside functions that are called (even indirectly) in the *try clause*. For example:: >>> def this_fails(): @@ -249,8 +257,9 @@ exception to occur. For example:: The sole argument to :keyword:`raise` indicates the exception to be raised. This must be either an exception instance or an exception class (a class that -derives from :class:`Exception`). If an exception class is passed, it will -be implicitly instantiated by calling its constructor with no arguments:: +derives from :class:`BaseException`, such as :exc:`Exception` or one of its +subclasses). If an exception class is passed, it will be implicitly +instantiated by calling its constructor with no arguments:: raise ValueError # shorthand for 'raise ValueError()' @@ -335,8 +344,7 @@ Most exceptions are defined with names that end in "Error", similar to the naming of the standard exceptions. Many standard modules define their own exceptions to report errors that may -occur in functions they define. More information on classes is presented in -chapter :ref:`tut-classes`. +occur in functions they define. .. _tut-cleanup: |