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