Python Course

Session 5

 

 

Table of Contents

Introduction

Exceptions

Examples

Extend list indexing to report None for index out-of-bounds

Loop printing the time every second until we ctrl-C

Catch different exceptions and take different actions for each

Reporting information passed with the raised eception

Raising an exception ourselves

And finally

Your own errors

 

Introduction

This session covers Python exceptions.

Exceptions

Python provides for the raising and handling of exceptions. An exception is used primarily for managing an error situation, but is also handy in other circumstances e.g. an exception is used internally to end loop iteration.

There are many predefined exceptions. Here's a short selection:

Name

Use

IndexError

Raised when a sequence subscript is out of range.

SyntaxError

Raised when the parser encounters a syntax error.

KeyboardInterrupt

Raised when the user hits the interrupt key.

 

When an exception is raised, the Python interpreter switches to a different mode of execution: rather than executing statements sequentially, it instead begins unwinding the stack of  nested function calls. As it does this, it checks at each stack level whether the particular exception has a “handler”, and if so then normal execution continues with that handler's code.

If no handler was encountered, the program exits and the interpreter reports the exception and provides a “back trace” of the nested function calls down to the point where the error occurred.

 

Examples

Extend list indexing to report None for index out-of-bounds

def index_or_none (lst, idx):

    """Return lst[idx], or None if idx is out of bounds."""

    try:

        return lst[idx]

    except IndexError:

        return None

 

test_lst = [0, 1, 2]

print(index_or_none(test_lst, 2))

print(index_or_none(test_lst, 3))

 

Input

Output

 

2

None

 

Loop printing the time every second until we ctrl-C

try:

    while True:

        print(time.strftime("%H:%M:%S", time.localtime()))

        # E.g.: 09:46:09

        time.sleep(1)

except KeyboardInterrupt:

    pass

 

Input

Output

 

 

 

Ctrl-C

09:46:09

09:46:10

09:46:11

 

 

Catch different exceptions and take different actions for each

mylist = ["Zero", "One", "Two"]

while True:

    try:

        instr = input("Enter an index:")

        print(mylist[int(instr)])

    except (KeyboardInterrupt, EOFError):

        print("\nOK, we're done")

        break

    except ValueError:

        print("Index must be an integer which \"{}\" "

              "is not".format(instr))

    except IndexError:

        print("Forgot to mention - index must be in range 0..{}, "

              "but you entered {}".format(len(mylist)-1, instr))


Note: we should really move the handler for KeyboardInterrupt outside the loop.

 

Input

Output

2

3

Two

Forgot to mention - index must be in range 0..2, but you entered 3

 

Reporting information passed with the raised eception

mylist = ["Zero", "One", "Two"]

while True:

    try:

        instr = input("Enter an index:")

        print(mylist[int(instr)])

    except (KeyboardInterrupt, EOFError):

        print("\nOK, we're done")

        break

    except (ValueError, IndexError) as err_info:

        print(err_info)

 

Input

Output

2

3

XYZ

Two

list index out of range

invalid literal for int() with base 10: 'XYZ'

 

Raising an exception ourselves

def GetInt(ask_str, reqd_range, patience_level=3):

    """ Ask for an integer in the required range and return it.

        Run out of patience if we keep getting bad input.

        Return the integer, or raise ValueError if we run out of

        patience, or if the user aborts.

    """

    for patience in range(patience_level):

        try:

            input_str = input(ask_str)

            idx = int(input_str)

            if idx in reqd_range:  return idx

            print("Value entered is not in the allowed range",

                  reqd_range.start, "..", reqd_range.stop-1)

        except (KeyboardInterrupt, EOFError):

            raise ValueError("You've given up.")

        except ValueError:

            print("Index must be an integer which \"{}\" "

                  "is not".format(input_str))

    raise ValueError("You've exceeded the failure tolerance "

                     "({} tries)".format(patience_level))

 

 

my_list = ["Zero", "One", "Two"]

try:

    idx = GetInt("Enter an Index:", range(0, len(my_list)))

    print(my_list[idx])

except ValueError as err_info:

    print(err_info)

 

Input

Output

2

Two

3

XYZ

45

Value entered is not in the allowed range 0 .. 2

Index must be an integer which "XYZ" is not

Value entered is not in the allowed range 0 .. 2

You've exceeded the failure tolerance (3 tries)

3

Ctrl-C

Value entered is not in the allowed range 0 .. 2

You've given up.

 

And finally

A couple of extra features.

You can handle an exception, do something (like report it), and then re-raise it. E.g.:

except ValueError:

    print("ValueError was raised")

    raise  # Let somebody else deal with the consequences.

 

The try ... except clause has some additonal parts to it, both of which are optional. Here's an example of the full clause:

try:

    Some statements that may raise an exception.

except some exceptions:

    Some code that deals with the exceptions (there can be

    multiple except parts).

else:

    Some statements that are executed if the try clause was

    successful (i.e. if no exception was raised).

finally:

    Some statements that are executed no matter what.

 

The finally part can be very useful for clean-up actions. If an exception was raised in the try part and isn't handled with an except part, the finally part is executed and Python re-raises the exception after executing the finally statements.

Your own errors

You can define your own exceptions. An exception is actually a class, which gets instantiated when it is raised. Here's an example of defining your very own FunnyError exception:

import traceback

class FunnyError(Exception):

    """Exception raised in strange circumstances.

    Attributes:

        msg  -- description of the problem

    """

    def __init__(self, msg):

        self.msg = msg

try:

    raise FunnyError("Something strange just happened here")

except FunnyError as funobj:

    traceback.print_exc()

 

Output:

Traceback (most recent call last):

  File "except.py", line 14, in <module>

    raise FunnyError("Something strange just happened here")

FunnyError: Something strange just happened here