Exception handling in Python

Exception Handling

There are at least two types of errors in the Python programming language: Syntax errors and Exceptions.

Syntax Errors

Syntax errors are sometimes referred to as parsing errors. These are fatal errors that occur when the code cannot be executed because of incorrect arguments passed to a function, typing or spelling error or incorrect indentation.

In most cases, the interpreter cannot run your code until the syntax errors are resolved. Syntax errors are similar to spelling and punctuation errors in natural languages.


>>> for number in range(5) print number
  File "<stdin>", line 1
    for number in range(5) print number
                               ^
SyntaxError: invalid syntax

In the example above, the parser repeats the offending line and displays a little arrow at the earliest point where the error was detected. The error is detected at the keyword print, here a colon ‘:’ is missing before it. The filename and number are printed to help you find the offending piece of code in a file.

Exceptions

Even if the syntax of your code is correct, it may cause an error when executed. These errors are called Exceptions. An exception occurs when Python knows what do do with the code but cannot perform the action. An example of code that could generate or ‘throw’ an exception is trying to open a nonexistent file. Python knows how to open the file but if it cannot find the file on the file system, it throws an exception.

# TypeError
>>> 4 + '4'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

# Input/Output Error

>>> fobj = open('directions-to-Azgard.txt')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'directions-to-Azgard.txt'

In the first instance, we attempted to add the integer 4 to a string ‘4’. Python knows how to add two numbers together and how to join strings, but in this case, it can’t add the two together because their types are different. The last line of the error message indicates what happened and the type of the exception is printed to the screen.

Exceptions can be expected and handled gracefully when they occur. Dealing with exceptions is referred to as Exception Handling.
If you know that a certain block of code might lead to an exception, you need to tell Python what to do if the exception is thrown. This is done through the use of a try statement.

try:
    age = int(raw_input(&quot;Enter your age: &quot;))
    print "You are {0} years old.".format(age)
except ValueError:
    print "Please enter a number"

Here, the raw_input() function asks for input from the user. We cannot trust that our user will input their age in the right format so we tell Python to ‘try’ or test the statement that requires user input. If the user’s input is a digit, then Python prints out a message telling them how old they are. If a ValueError exception (invalid value) is encountered, the except clause is executed:

Enter your age: five
Please enter a number.

The except statement tells Python to look out for a ‘ValueError’ exception. The Python documentation has a list of built in Exceptions here. It is also possible to not specify what kind of error you’re trying to catch:

try:
    age = int(raw_input("Enter your age: "))
    print "You are {0} years old.".format(age)
except:
    print "Please enter a number"

This type of exception is a bare except and should be avoided. The reason for this is that it catches any and all exceptions so you wouldn’t know what exception you’re catching. Using except ValueError: shows that you’re trying to catch ValueErrors and nothing else.

The try ... except statement has an optional else which when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception:

try:
    age = int(raw_input("Enter your age: "))
    print "You are {0} years old.".format(age)
except ValueError:
    print "Please enter a number"
else:
    print "An error did not occur" 

Raising Exceptions

Python allows you to create or to force an exception to occur using the raise statement:

>>> raise ValueError('Value error occurred')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Value error occurred

Cleaning Up

The try statement has another optional clause which runs every-time, whether an exception was raised or not:

>>> def maths(a,b):
	try:
		result = a / b
	except ZeroDivisionError:
		print "You cannot divide a number by zero"
	else:
		print "The result is", result
	finally:
		print "We are done here, exiting finally clause"

		
>>> maths(6,2)
The result is 3
We are done here, exiting finally clause
>>> maths(6,0)
You cannot divide a number by zero
We are done here, exiting finally clause
>>> maths("2", "1")
We are done here, exiting finally clause

Traceback (most recent call last):
  File "<pyshell#27>", line 1, in <module>
    maths("2", "1")
  File "<pyshell#24>", line 3, in maths
    result = a / b
TypeError: unsupported operand type(s) for /: 'str' and 'str'

The finally clause is executed no matter what. The TypeError was not handled so it was raised after the finally clause was executed. finally is useful for releasing resources after the try ...except ..finally block has been executed.

Conclusion

Writing Exception Handling code is simple to do and should be part of your work flow. When your code raises an exception, you can now deal with the exception and exit your program gracefully.