The Python Class/Exceptions
What makes up an exception?
[edit | edit source]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 | edit source]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 | edit source]
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 | edit source]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 | edit source]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.')