The Python Class/Exceptions

From Wikibooks, open books for an open world
Jump to navigation Jump to search

What makes up an exception?[edit]

All exceptions have to be derived from BaseException. In an analogy, this could be the world. There are 4-5 derivatives of BaseException, which are Exception, KeyboardInterrupt, SystemExit and a few others that are exit exceptions.

When you use the except part of a try/except, it will intercept any exceptions of the exceptions type and in the sub exceptions. This is useful because if you wanted to stop all error exceptions, you would use except:. However, this also blocks SystemExit (run by exit()) and KeyboardInterrupt (activated by doing Ctrl/Cmd/...+C), which we would not want to block because then the program could not exit automatically (you would have to click on the x).

We could do except Exception:, and this is perfect because you can still exit, but it will not let any errors such as ValueErrors stop your program.

If we only want to block all ValueErrors, we would just do except ValueError:. This matters because when you make your own exceptions, you dont want your exception to be stopped by other exceptions (most of the time).

Creating a custom exception[edit]

When we create a class, in order to make it an exception, we need to make it a subclass of an existing class. This is where the parentheses come in. You can either define classes as

class x:
    pass

or

class x():
    pass

However, a parent class can go into the parentheses to make it a subclass. In an exception, it would be

class x(Exception):
    pass

Now, if we were to try raising the x without the Exception, we would get TypeError: exceptions must derive from BaseException. If we were to raise the one with the exception, we would get

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.x

Giving it a message[edit]

Sure, if properly named, your exception might help. However, you might want to include an error message or pass variable values in to help the user figure out the problem. To do this, we have to access the exception's __init__. We pass in our message in our own __init__ function.

class x(Exception):
    def __init__(self):
        Exception.__init__(self, 'This is a test')

Now if we were to raise x it would say:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.x: This is a test

It now has a message.

Sub-classing another exception[edit]

To subclass another exception, just replace x with the Exception's class. For example, if we wanted to make y, we would write

class x(Exception):
    def __init__(self):
        Exception.__init__(self, 'This is a test')

class y(x):
    def __init__(self):
        Exception.__init__(self, 'This is another test')

Why would we subclass?[edit]

Subclassing is a good idea because then you can skip only the exceptions that come with certain operations, such as file reading. Let's make an exception that will raise if a file is too big.

class TooBigFile(OSError):
    def __init__(self, filesize):
        Exception.__init__(self, 'The file is too big. It is '+str(filesize)+' bytes.')

If we wanted to make a program that will skip all OS errors, including this one if there are any problems, we would write except OSError:.

try:
    with open('somefile.txt', 'r') as file:
        contents = file.read()
        if len(contents) > 1024 ** 3: #**1 for kb, **2 for mb, and **3 for gb
            raise TooBigFile(len(contents))
except OSError:
    print('Did not do the file stuff because there was an error while opening/reading the file.')