summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2022-04-13 20:45:33 (GMT)
committerGitHub <noreply@github.com>2022-04-13 20:45:33 (GMT)
commit04f9658c591f61f0d45ab1a818840a4c4ef82f64 (patch)
tree42cdce4742895dd4ba0dd5aad043b1934fcb689e
parent3fc57e8f6ff925b561b03c46bcf5bd323782c19c (diff)
downloadcpython-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.rst100
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: