Chapter 9: User-defined exceptions

Exception class hierarchy

face Josiah Wang

We will end our core lessons by returning to object-oriented programming, more specifically on the topic of inheritance. Hopefully you still remember what that is!

Remember that in Lesson 9, I mentioned that Python exceptions are instances of the Exception class.

I also showed you the class hierarchy for Exceptions in Lesson 9. Click on the following button if you wish to view them again.

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

Now that you understand inheritance, this hierarchy make even more sense: a ZeroDivisionError is a subclass of ArithmeticError, which in turn is a subclass of Exception, which is a subclass of BaseException (the root of all Python exceptions).

Order of Exceptions

There is one thing you need to be aware of when you have multiple except clauses. The more general Exceptions should come after the more specific ones. If you run the code below, it should print out ZeroDivisionError as expected.

try:
    x = 5 / 0
except ZeroDivisionError:
    print("ZeroDivisionError")
except ArithmeticError:
    print("ArithmeticError")
except Exception:
    print("Exception")

But what happens when you run the following code? Make a guess!

try:
    x = 5 / 0
except Exception:
    print("Exception")
except ArithmeticError:
    print("ArithmeticError")
except ZeroDivisionError:
    print("ZeroDivisionError")

When you run the code, it should print out only Exception. This is because ZeroDivisionError is a subclass of Exception, so it is technically an instance of Exception. Therefore, it will not check any further.

So beware of this subtlety! Of course, you should try NOT to have so many except clauses in the first place, but keep each try... except block as small and as specific as you can!