Python Course
Session 5
Catch different exceptions and take different actions for each |
This session covers Python 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.
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 |
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
|
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 |
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' |
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. |
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.
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