© Paul Gerrard 2016
Paul GerrardLean Python10.1007/978-1-4842-2385-7_7

7. Exception and Error Handling

Paul Gerrard
(1)
Maidenhead, Berkshire, UK
 

Exceptions and Errors

Things can go wrong in your code for many reasons. One reason is that the programmer has written some code that is faulty. Faults, defects, and bugs are labels we put on aspects of our program code that are not quite right. Faults occur because we, as programmers, are not perfect. We are human and are always going to get some things wrong. Early on in your programming career, you will learn that all is not plain sailing.1
Sometimes, you can control the input data and behavior of your programs, but the sheer number of ways in which your code can be dealt a curveball overwhelms your ability to deal with them. Out of this challenge came the approach called defensive programming.2
Defensive programming isn’t a timid approach or lackluster attitude. It is a discipline that tackles the possibility of failure head on. A significant part of this discipline is the effective implementation of error and exception handling.
Let’s look at an example. Suppose you had some code that implemented the division operation such as this:
quotient = a / b
What could possibly go wrong? Well the obvious problem occurs if the value of b is zero. What would we see?
>>> quotient = 73 / 0.0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero
>>>
The text ZeroDivisionError: float division by zero is what we are interested in. The Python interpreter raises an error ZeroDivisionError and provides an error message, albeit a rather terse one.
If this code fragment was in the middle of a program, the program would fail and terminate. That’s not of much use to us if we want the program to handle the error and move on to the next calculation. We use the term error handling or more often, exception handling, to refer to how we do this.
Python has many built-in exception types—ZeroDivisionError is just one of them—and we can trap these occurrences and deal with this in our code. Here’s an example program division.py:
1   print('Input two numbers. the first will be divided by the second')
2   
3   afirst = input('first number:')
4   first=float(afirst)
5   asecond = input('second number:')
6   second = float(asecond)
7   
8   quotient = first / second
9   print('Quotient first/second = ',quotient)
If you run this, enter say, 1 and 2 you get a result of 0.5, no problem. If you enter 1 and 0, you get the ZeroDivisionError message again.
Here’s a new version of the program, divisionHandled.py.
1   print('Input two numbers. The first will be divided by the second')
2   
3   afirst = input('1st number:')
4   asecond = input('2nd number:')
5   
6   try:
7       first=float(afirst)
8       second = float(asecond)
9       quotient = first / second
10      print('Quotient 1st/2nd = ',quotient)
11  except Exception as diag:
12      print(diag.__class__.__name__,':',diag)
In this case, we have enclosed some of the code (the two text-to-float number conversions and the division) inside a try: clause on line 6. If any code inside the try: clause raises an error, it is trapped by the except: clause on line 11.
The except: clause identifies an exception type and optionally, a variable into which the exception data is stored. Exception is the top-level class for error type so it captures all errors. In the except code block, the code prints the diag.__class__.__name__ attribute, which names the error type.
So far, so good. If you play with this program you can try entering poor data, as shown here.
D:LeanPythonprograms>python divisionHandled.py
Input two numbers. The first will be divided by the second
1st number:
2nd number:
ValueError : could not convert string to float:
D:LeanPythonprograms>python divisionHandled.py
Input two numbers. The first will be divided by the second
1st number:1
2nd number:0
ZeroDivisionError : float division by zero
In the first run, the float conversion code fails. We know it is the first conversion by looking at the code, but an end user who didn’t know the code might get confused. In general, therefore, it is recommended that:
  • We handle particular errors rather than have a catch-all.
  • Give each section of code its own exception handler to localize the error.
Here is the final version of our fully error-handled code: divisionHandledV2.py.
1   print('Input two numbers. The first will be divided by the second')
2   
3   afirst = input('1st number:')
4   try:
5     first=float(afirst)
6     asecond = input('2nd number:')
7     try:
8       second = float(asecond)
9       try:
10        quotient = first / second
11        print('Quotient 1st/2nd = ',quotient)
12      except ZeroDivisionError as diag:
13        print(diag,': 2nd number must be non-zero')
14    except ValueError as diag:
15      print(diag,'2nd number')
16  except ValueError as diag:
17      print(diag,'1st number')
The slightly tricky part is that it is hard to know what error types will occur until you test for them, so the general approach might be this:
  • First, capture all exceptions in places where you expect them to occur.
  • Second, test for all the exceptions you can think of, trigger them, and make a note where they occur.
  • For each exception type you find, create an exception clause specific to that exception.
By the way, note that it is possible to trap multiple exception types if you put them in a tuple; for example:
except (ValueError, ZeroDivisionError) [as e]:
The obvious alternative to handling errors that occur is to be more stringent on the validation of input data. In the preceding example, it might be a better alternative. In some circumstances, though, the exception cannot be checked for ahead of time because the data values that cause the exception are the result of intermediate calculations that might not be easily predicted.
The range of exception types is large. They cover things like type conversions, arithmetic, file I/O, database access, dictionary and list element violations, and so on. The full list is presented in the Appendix.
Footnotes
1
It could be said you don’t learn by getting things right. You only learn from your mistakes. You are going to make a lot of mistakes; that’s not the problem. The problem comes if you do not learn from them. A mantra that you might learn from is, “Fail Fast!” and learn from failure.
 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.22.179