|
| 1 | +Exceptions |
| 2 | +========== |
| 3 | + |
| 4 | +This section deals with exceptions, which are language functions that |
| 5 | +specifically handle unusual circumstances during the execution of a programme. |
| 6 | +The most common exception is error handling, but they can also be used |
| 7 | +effectively for many other purposes. Python provides a comprehensive set of |
| 8 | +exceptions, and you can define new exceptions for your own purposes. |
| 9 | + |
| 10 | +An exception is an object that is automatically created by Python functions with |
| 11 | +a :ref:`raise <python3:raise>` statement, for example with: |
| 12 | + |
| 13 | +.. literalinclude:: exceptions.py |
| 14 | + :language: python |
| 15 | + :linenos: |
| 16 | + :lines: 11-12 |
| 17 | + :lineno-start: 11 |
| 18 | + |
| 19 | +The :ref:`raise <python3:raise>` statement causes the Python programme to be |
| 20 | +executed in a different way than is usually intended: The current call chain is |
| 21 | +searched for a handler that can handle the generated exception. If such a |
| 22 | +handler is found, it is called and can access the exception object to obtain |
| 23 | +further information, as in our :class:`EmptyFileError` example: |
| 24 | + |
| 25 | +.. literalinclude:: exceptions.py |
| 26 | + :language: python |
| 27 | + :linenos: |
| 28 | + :lines: 1-2 |
| 29 | + |
| 30 | +This defines your own exception type, which inherits from the ``Exception`` base |
| 31 | +type. |
| 32 | + |
| 33 | +You can find an overview of the class hierarchy of built-in exceptions at |
| 34 | +`Exception hierarchy |
| 35 | +<https://docs.python.org/3/library/exceptions.html#exception-hierarchy>`_ in the |
| 36 | +Python documentation. Each exception type is a Python class that inherits from |
| 37 | +its parent exception type. For example, a ``ZeroDivisionError`` is also an |
| 38 | +``ArithmeticError``, an ``Exception`` and also a ``BaseException`` by |
| 39 | +inheritance. This hierarchy is intentional: most exceptions inherit from |
| 40 | +``Exception``, and it is strongly recommended that all user-defined exceptions |
| 41 | +also subclass ``Exception`` and not ``BaseException``: |
| 42 | + |
| 43 | +It is possible to create different types of exceptions to reflect the actual |
| 44 | +cause of the reported error or exceptional circumstance. |
| 45 | + |
| 46 | +.. literalinclude:: exceptions.py |
| 47 | + :language: python |
| 48 | + :linenos: |
| 49 | + :lines: 8-16 |
| 50 | + :lineno-start: 8 |
| 51 | + |
| 52 | +If an ``OSError`` or an ``EmptyFileError`` occurs in the ``try`` block during |
| 53 | +the execution of :func:`open`, the corresponding ``except`` block is executed. |
| 54 | + |
| 55 | +If no suitable exception handler is found, the programme terminates with an |
| 56 | +error message. We therefore add ``else`` and ``finally`` to our |
| 57 | +``try``-``except`` statements: |
| 58 | + |
| 59 | +.. literalinclude:: exceptions.py |
| 60 | + :language: python |
| 61 | + :linenos: |
| 62 | + :lines: 17-21 |
| 63 | + :lineno-start: 17 |
| 64 | + |
| 65 | +Now we can define a list of different file types so that our complete code looks |
| 66 | +like this: |
| 67 | + |
| 68 | +.. literalinclude:: exceptions.py |
| 69 | + :language: python |
| 70 | + :linenos: |
| 71 | + :lines: 1- |
| 72 | + :lineno-start: 1 |
| 73 | + |
| 74 | +Line 7 |
| 75 | + If an ``OSError`` or ``EmptyFileError`` occurs during the execution of the |
| 76 | + statements in the ``try`` block, the corresponding ``except`` block is |
| 77 | + executed. |
| 78 | +Line 9 |
| 79 | + An ``OSError`` could be triggered here. |
| 80 | +Line 12 |
| 81 | + Here you trigger the ``EmptyFileError``. |
| 82 | +Line 17 |
| 83 | + The ``else`` clause is optional; it is executed if no exception occurs in |
| 84 | + the ``try`` block. |
| 85 | +Line 19 |
| 86 | + The ``finally`` clause is also optional and is executed at the end of the |
| 87 | + block, regardless of whether an exception was triggered or not. |
| 88 | + |
| 89 | +.. note:: |
| 90 | + The way Python handles error situations in general differs from some other |
| 91 | + languages, such as Java. These languages check possible errors as far as |
| 92 | + possible before they occur, as handling exceptions after they occur is |
| 93 | + costly. This is sometimes referred to as the :abbr:`LBYL (Look before you |
| 94 | + leap)` approach. |
| 95 | + |
| 96 | + Python, on the other hand, relies more on exceptions to handle errors after |
| 97 | + they occur. Although this reliance may seem risky, when exceptions are used |
| 98 | + correctly, the code is less cumbersome and easier to read, and errors are |
| 99 | + only handled when they occur. This Pythonic approach to error handling is |
| 100 | + often described as :abbr:`EAFP (easier to ask forgiveness than permission)`. |
| 101 | + |
| 102 | +Checks |
| 103 | +------ |
| 104 | + |
| 105 | +* Write code that receives two numbers and divides the first number by the |
| 106 | + second. Check if the :class:`python3:ZeroDivisionError` occurs when the second |
| 107 | + number is ``0`` and catch it. |
| 108 | + |
| 109 | +* If :class:`MyError` inherits from :class:`Exception`, what is the difference |
| 110 | + between ``except Exception as e`` and ``except MyError as e``? |
| 111 | + |
| 112 | +* Write a simple program that receives a number and then uses the :func:`assert` |
| 113 | + statement to throw an :class:`exception <python3:Exception>` if the number is |
| 114 | + ``0``. |
| 115 | + |
| 116 | +* Writes a user-defined exception :class:`Outliers` that throws an exception if |
| 117 | + the variable ``x`` is greater or less than ``3``? |
| 118 | + |
| 119 | +* Is the check whether an object is a list (:ref:`Check: list <check-list>`) |
| 120 | + programming in the style of :abbr:`LBYL (look before you leap)` or |
| 121 | + :abbr:`EAFP (easier to ask forgiveness than permission)`? |
0 commit comments