Handling a File Error

As already pointed out in the exceptions lesson, Python contains a vast set of built-in exceptions. One important class has to do with file handling. The example presented in the lesson will help to review file handling methods and put them in the context of handling exceptions.

Raising Custom Exceptions

When you are developing your own packages, it is often useful to define some common exceptions. This gives a great deal of flexibility because it allows other developers to handle those exceptions as they find appropriate. Let's see an example. Imagine that you want to write a function that calculates the average between two numbers, but you want both numbers to be positive. This is the same example that we have seen when working with decorators. We start by defining the function:

def average(x, y):
    return (x + y)/2

And now we want to raise an Exception if either input is negative. We can do the following:

def average(x, y):
    if x<=0 or y<=0:
        raise Exception('Both x and y should be positive')
    return (x + y)/2

If you try it yourself with a negative input, you will see the following printed:

Exception: Both x and y should be positive

Which is great, it even points to the line number with the issue, etc. However, if you are building a module and you expect others to use it, it would be much better to define a custom Exception, that can be explicitly caught. It is as easy as this:

class NonPositiveError(Exception):
    pass

def average(x, y):
    if x <= 0 or y <= 0:
        raise NonPositiveError('Both x and y should be positive')
    return (x + y) / 2

An exception is a class, and therefore it should inherit from the general Exception class. We don't really need to customize anything at this stage, we just type  pass in the body of the class. If we run the code above with a negative value, we will get:

NonPositiveError: Both x and y should be positive

If you want to catch that exception in downstream code, you will do it as always. The only difference is that custom exceptions are not available by default and you should import them. For example, you would do the following:

from exceptions import NonPositiveError
from tools import average

try:
    avg = average(1, -2)
except NonPositiveError:
    avg = 0

If you have worked long enough with packages, probably you have already encountered a lot of different exceptions. They are a great tool to let the user know exactly what was wrong and act accordingly. Sometimes we can be prepared for some exceptions and is very appreciated when custom ones are included into the package and not just a generic one that forces us to catch any exception, even if it is something that we were not actually expecting.