Exception Hierarchy Python (58/100 Days of Python)
In Python, exceptions are a way to handle errors and other exceptional events that may occur during program execution. Python’s exception hierarchy provides a well-organized way to categorize and handle different types of exceptions. The defined exception structure also provides a deterministic way of handling different types of exceptions with except
blocks.
The Exception Hierarchy
In Python, all exceptions are derived from the BaseException
class. This means that every exception in Python is an instance of BaseException
or one of its subclasses.
The BaseException
class is the top-level class in the exception hierarchy. It provides some common methods that all exceptions can use, such as __str__
and __repr__
. However, you should not use BaseException
directly in your code as it is too broad and can catch any type of exception.
Instead, you should use more specific exception classes that are subclasses of BaseException
. Python provides a number of built-in exception classes that you can use, and you can also create your own custom exception classes.
The following diagram shows the hierarchy of built-in exception classes in Python (taken from the official Python documentation):
BaseException
├── BaseExceptionGroup
├── GeneratorExit
├── KeyboardInterrupt
├── SystemExit
└── Exception
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── BufferError
├── EOFError
├── ExceptionGroup [BaseExceptionGroup]
├── 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
├── StopAsyncIteration
├── StopIteration
├── SyntaxError
│ └── IndentationError
│ └── TabError
├── SystemError
├── TypeError
├── ValueError
│ └── UnicodeError
│ ├── UnicodeDecodeError
│ ├── UnicodeEncodeError
│ └── UnicodeTranslateError
└── Warning
├── BytesWarning
├── DeprecationWarning
├── EncodingWarning
├── FutureWarning
├── ImportWarning
├── PendingDeprecationWarning
├── ResourceWarning
├── RuntimeWarning
├── SyntaxWarning
├── UnicodeWarning
└── UserWarning
This means that the FileNotFoundError
is a subclass of an OSError
, which is a subclass of the Exception
class, which itself inherits from the BaseException
.
Handling multiple exceptions with a single except
statement
To handle multiple exceptions with a single except
statement, you can specify a tuple of exception types to catch, like this:
try:
# some code that may raise an exception
except (ExceptionType1, ExceptionType2):
# handle the exception
In this example, both ExceptionType1
and ExceptionType2
are exceptions that you want to catch. If the code in the try
block raises an instance of either of these exceptions, the code in the except
block will execute.
Here’s an example with specific exception types:
try:
# some code that may raise an exception
except (TypeError, ValueError):
# handle the exception
In this example, if the code in the try
block raises either a TypeError
or a ValueError
, the code in the except
block will execute.
Handling multiple exceptions with multiple except
statements
Alternatively, you can handle multiple exceptions with multiple except
statements. In this case, each except
statement handles a different exception type:
try:
# some code that may raise an exception
except TypeError:
# handle the TypeError
except ValueError:
# handle the ValueError
In this example, if the code in the try
block raises a TypeError
, the code in the first except
block will execute. If the code raises a ValueError
, the code in the second except
block will execute.
Respecting the exception hierarchy
When using multiple except
statements, it's important to respect the exception hierarchy in Python. This means that if you catch a base exception class, such as Exception
, you should catch more specific exceptions before it. If you write an except
statement of a more specific class after the base class, the block won’t be executed:
try:
# some code that may raise an exception
except ValueError:
# handle the ValueError
except Exception:
# handle any other exception
In this example, the ValueError
exception is caught first. If the code raises any other exception that is derived from Exception
, the code in the second except
block will execute.
However, it is not recommended to catch Exception
directly, as it is too broad and can catch any type of exception. It's better to catch more specific exceptions whenever possible:
try:
# some code that may raise an exception
except TypeError:
# handle the TypeError
except ValueError:
# handle the ValueError
except Exception:
# handle any other exception
In this example, if the code in the try
block raises a TypeError
or a ValueError
, the corresponding except
block will execute. If the code raises any other exception that is derived from Exception
, the code in the third except
block will execute.
If we place the base exception as the first except
block, it will prevent the rest from being ever executed:
try:
# some code that may raise an exception
except Exception as e:
print(f'An error occurred: {e}') # This will catch all the errors
except ValueError:
print('A ValueError occurred') # This will never be executed
except TypeError:
print('A TypeError occurred') # This will never be executed
In this example, the try
block may raise any type of exception. However, the first except
statement catches the base Exception
class, so it will catch any exception that is raised. The error message will be printed and the rest of the except
statements will not be executed.
What’s next?
- If you found this story valuable, please consider clapping multiple times (this really helps a lot!)
- Hands-on Practice: Free Python Course
- Full series: 100 Days of Python
- Previous topic: Exception Handling
- Next topic: Custom Exceptions