6.3. Exception Catching

def mean(data):
try:

avg = sum(data) / len(data)

except TypeError:

print(f'Invalid type of an argument: {data}')

except ZeroDivisionError:

print('Empty data')

else:

print(avg)

finally:

...

6.3.1. Catching Exceptions

  • try

  • except

  • else

  • finally

  • try is required and then one of the others blocks

    >>> try:
    ...     'Try to execute'
    ... except Exception:
    ...     'What to do if exception occurs'
    ... else:
    ...     'What to do if no exception occurs'
    ... finally:
    ...     'What to do either if exception occurs or not'
    'Try to execute'
    'What to do if no exception occurs'
    'What to do either if exception occurs or not'
    

Catch single exception:

>>> def apollo13():
...     raise RuntimeError('Oxygen tank explosion')
>>>
>>>
>>> try:
...     apollo13()
... except RuntimeError:
...     print('Houston we have a problem')
Houston we have a problem

Catch many exceptions with the same handling:

>>> def apollo13():
...     raise RuntimeError('Oxygen tank explosion')
>>>
>>>
>>> try:
...     apollo13()
... except (RuntimeError, TypeError, NameError):
...     print('Houston we have a problem')
Houston we have a problem

Catch many exceptions with different handling:

>>> try:
...     with open(r'/tmp/my-file.txt') as file:
...         print(file.read())
... except FileNotFoundError:
...     print('File does not exist')
... except PermissionError:
...     print('Permission denied')
File does not exist

Exceptions logging:

>>> import logging
>>>
>>>
>>> def apollo13():
...     raise RuntimeError('Oxygen tank explosion')
>>>
>>>
>>> try:
...     apollo13()
... except RuntimeError as err:
...     logging.error(err)
... #stderr: ERROR:root:Oxygen tank explosion

6.3.2. Else and Finally

  • else is executed when no exception occurred

  • finally is executed always (even if there was exception)

else is executed when no exception occurred:

>>> def apollo11():
...     print('Try landing on the Moon')
>>>
>>>
>>> try:
...     apollo11()
... except Exception:
...     print('Abort')
... else:
...     print('Landing a man on the Moon')
Try landing on the Moon
Landing a man on the Moon

finally is executed always (even if there was exception): Used to close file, connection or transaction to database:

>>> try:
...     file = open('/tmp/myfile.txt')
... except Exception:
...     print('Error, file cannot be open')
... finally:
...     print('Close file')
Error, file cannot be open
Close file
>>> def apollo11():
...     print('Try landing on the Moon')
>>>
>>>
>>> try:
...     apollo11()
... except Exception:
...     print('Abort')
... finally:
...     print('Returning safely to the Earth')
Try landing on the Moon
Returning safely to the Earth
>>> def apollo11():
...     print('Program P63 - Landing Manoeuvre Approach Phase')
...     raise RuntimeError('1201 Alarm')
...     raise RuntimeError('1202 Alarm')
...     print('Contact lights')
...     print('The Eagle has landed!')
...     print("That's one small step for [a] man, one giant leap for mankind.")
>>>
>>>
>>> try:
...     apollo11()
... except RuntimeError:
...     print("You're GO for landing")
... except Exception:
...     print('Abort')
... else:
...     print('Landing a man on the Moon')
... finally:
...     print('Returning safely to the Earth')
Program P63 - Landing Manoeuvre Approach Phase
You're GO for landing
Returning safely to the Earth

6.3.3. Pokemon Exception Handling

  • "Gotta catch 'em all"

  • Ctrl-C raises KeyboardInterrupt

User cannot simply kill program with Ctrl-C:

>>> def input(__prompt):
...     """Stub user input, for testing purpose only"""
...     return ''
>>>
>>>
>>> # doctest: +SKIP
... while True:
...     try:
...         number = float(input('Type number: '))
...     except:
...         continue

User can kill program with Ctrl-C:

>>> def input(__prompt):
...     """Stub user input, for testing purpose only"""
...     return ''
>>>
>>>
>>> # doctest: +SKIP
... while True:
...     try:
...         number = float(input('Type number: '))
...     except Exception:
...         continue

6.3.4. Assignments

Code 6.3. Solution
"""
* Assignment: Exception Catch Except
* Complexity: easy
* Lines of code: 4 lines
* Time: 3 min

English:
    1. Use data from "Given" section (see below)
    2. Convert value passed to the `check` function as a `float`
    3. If conversion fails then print 'Invalid value'
    4. Non-functional requirements
        a. Write solution inside `check` function
        b. Mind the indentation level
    5. Compare result with "Tests" section (see below)

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Przekonwertuj wartośc przekazaną do funckji `check` jako `float`
    3. Jeżeli konwersja się nie powiedzie to wypisz 'Invalid value'
    4. Wymagania niefunkcjonalne
        a. Rozwiązanie zapisz wewnątrz funkcji `check`
        b. Zwróć uwagę na poziom wcięć
    5. Porównaj wyniki z sekcją "Tests" (patrz poniżej)

Tests:
    >>> check('1')
    >>> check('1.0')
    >>> check('1,0')
    Invalid value
"""


# Given
def check(value):
    ...


Code 6.4. Solution
"""
* Assignment: Exception Catch Else
* Complexity: easy
* Lines of code: 7 lines
* Time: 5 min

English:
    1. Use data from "Given" section (see below)
    2. Convert value passed to the `check` function as a `float`
    3. If conversion fails, raise `TypeError`
    4. If value is below AGE, raise `PermissionError`
    5. Non-functional requirements
        a. Write solution inside `check` function
        b. Mind the indentation level
    6. Compare result with "Tests" section (see below)

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Przekonwertuj wartośc przekazaną do funckji `check` jako `float`
    3. Jeżeli konwersja się nie powiedzie, podnieś `TypeError`
    4. Jeżeli wartość jest poniżej AGE, podnieś `PermissionError`
    5. Wymagania niefunkcjonalne
        a. Rozwiązanie zapisz wewnątrz funkcji `check`
        b. Zwróć uwagę na poziom wcięć
    6. Porównaj wyniki z sekcją "Tests" (patrz poniżej)

Tests:
    >>> check(21)
    >>> check('one')
    Traceback (most recent call last):
    TypeError
    >>> check(1)
    Traceback (most recent call last):
    PermissionError
"""

# Given
ADULT = 18


def check(age):
    ...


Code 6.5. Solution
"""
* Assignment: Exception Catch Finally
* Complexity: easy
* Lines of code: 8 lines
* Time: 8 min

English:
    1. Use data from "Given" section (see below)
    2. Convert value passed to the function as a `int`
    3. If conversion fails, raise exception `TypeError` with message:
        'Invalid type, expected int or float'
    4. Use `finally` to print `degree` value
    5. Non-functional requirements
        a. Write solution inside `check` function
        b. Mind the indentation level
    6. Compare result with "Tests" section (see below)

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Przekonwertuj wartośc przekazaną do funckji jako `int`
    3. Jeżeli konwersja się nie powiedzie to podnieś wyjątek `TypeError`
        z komunikatem 'Invalid type, expected int or float'
    4. Użyj `finally` do wypisania wartości `degree`
    5. Wymagania niefunkcjonalne
        a. Rozwiązanie zapisz wewnątrz funkcji `check`
        b. Zwróć uwagę na poziom wcięć
    6. Porównaj wyniki z sekcją "Tests" (patrz poniżej)

Tests:
    >>> check(1)
    1
    >>> check(180)
    180
    >>> check(1.0)
    1
    >>> check('one')
    Traceback (most recent call last):
    TypeError: Invalid type, expected int or float
"""


# Given
def check(value):
    ...