8.4 Exception Hierarchy in Python
In Python, exceptions are objects that represent errors during the execution of a program. These exceptions are organized in a structured exception hierarchy, where all exception classes inherit from a common base class. Understanding the exception hierarchy is important for catching and handling specific exceptions in a more controlled way, allowing you to address different types of errors appropriately.
In this section, we will explore Python’s exception hierarchy, focusing on the relationships between the various exception classes, and how to work with them effectively.
8.4.1 The Base Class: BaseException
At the top of Python’s exception hierarchy is the BaseException
class. All built-in exceptions inherit from BaseException
, making it the root class for all exceptions in Python.
BaseException
: The base class for all exceptions. You typically do not catch this exception directly unless you are writing specialized error-handling code.
Example:
try:
raise Exception("This is a custom exception")
except BaseException as e:
print(f"Caught BaseException: {e}")
In this example:
BaseException
is used to catch all types of exceptions, but it's usually not recommended because it can catch exceptions that should generally be handled differently (likeKeyboardInterrupt
orSystemExit
).
8.4.2 Common Subclasses of BaseException
Directly inheriting from BaseException
are a few important exceptions, most notably Exception
, SystemExit
, KeyboardInterrupt
, and GeneratorExit
. These exceptions serve specific purposes:
Exception
: The most commonly used base class for all built-in, user-defined, and custom exceptions. You will usually catch exceptions derived fromException
.SystemExit
: Raised when the program is exiting (e.g., when callingsys.exit()
).KeyboardInterrupt
: Raised when the user interrupts program execution, typically by pressingCtrl+C
.GeneratorExit
: Raised when a generator or coroutine is closed.
8.4.3 The Exception
Class
The Exception
class is the parent class for most exceptions that are raised during the execution of a program. You will catch exceptions derived from this class for most error handling in Python.
Exception
: The base class for all standard exceptions. You can catch this class to handle most common errors, but it’s usually better to catch more specific exceptions.
Example:
try:
x = 1 / 0
except Exception as e:
print(f"Caught Exception: {e}")
In this example:
Exception
catches the specific exceptionZeroDivisionError
because it inherits fromException
.
8.4.4 Common Built-In Exception Classes
Python provides many built-in exception classes that inherit from Exception
. Here are some of the most commonly used ones:
ArithmeticError
: Base class for errors related to numeric operations.ZeroDivisionError
: Raised when division by zero is attempted.OverflowError
: Raised when a numerical result is too large to be represented.FloatingPointError
: Raised for floating-point arithmetic errors.
LookupError
: Base class for errors related to lookups (e.g., accessing elements in sequences or mappings).IndexError
: Raised when an index is out of range in a list, tuple, or similar.KeyError
: Raised when a dictionary key is not found.
ValueError
: Raised when an operation receives an argument of the right type but with an inappropriate value.TypeError
: Raised when an operation or function is applied to an object of inappropriate type.NameError
: Raised when a local or global name is not found.UnboundLocalError
: Raised when a local variable is referenced before it has been assigned a value.
IOError
: Raised when an input/output operation fails (e.g., file handling). In Python 3,IOError
is an alias forOSError
.OSError
: Base class for operating system-related errors (e.g., file system errors, permission errors).FileNotFoundError
: Raised when a file or directory is requested but cannot be found.
RuntimeError
: Raised when an error does not fall into any other category.RecursionError
: Raised when the maximum recursion depth is exceeded.
Example of Specific Exceptions:
try:
my_list = [1, 2, 3]
print(my_list[10]) # Raises IndexError
except IndexError as e:
print(f"IndexError caught: {e}")
In this example:
IndexError
is caught specifically, allowing more precise handling of the error.
8.4.5 Catching Multiple Exceptions
You can handle multiple exceptions in a single try
block by specifying multiple exception types in an except
clause.
Example: Catching Multiple Exceptions:
try:
value = int("abc") # Raises ValueError
except (ValueError, TypeError) as e:
print(f"Caught ValueError or TypeError: {e}")
In this example:
- Both
ValueError
andTypeError
are caught by the sameexcept
block.
You can also chain multiple except
blocks to handle each exception type separately.
Example:
try:
value = int("abc")
except ValueError:
print("Caught a ValueError")
except TypeError:
print("Caught a TypeError")
In this case:
ValueError
andTypeError
are handled in separate blocks, allowing different responses for each type of exception.
8.4.6 Custom Exceptions
In Python, you can define your own exceptions by creating a custom class that inherits from the Exception
class or one of its subclasses. This is useful when you need to raise specific errors in your application.
Example: Defining a Custom Exception:
class InvalidAgeError(Exception):
def __init__(self, age, message="Invalid age provided"):
self.age = age
self.message = message
super().__init__(self.message)
# Using the custom exception
def validate_age(age):
if age < 0:
raise InvalidAgeError(age)
print(f"Valid age: {age}")
try:
validate_age(-5)
except InvalidAgeError as e:
print(f"Caught custom exception: {e}")
In this example:
- The custom exception
InvalidAgeError
inherits fromException
and is raised when the input age is invalid (e.g., negative). - The
InvalidAgeError
includes custom attributes and a default message.
8.4.7 The Complete Python Exception Hierarchy
Here’s a simplified version of Python’s exception hierarchy:
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── ArithmeticError
│ ├── ZeroDivisionError
│ ├── OverflowError
│ └── FloatingPointError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── ValueError
├── TypeError
├── NameError
│ └── UnboundLocalError
├── OSError
│ └── FileNotFoundError
├── RuntimeError
│ └── RecursionError
└── ...
8.4.8 Summary
BaseException
is the top-level class in Python’s exception hierarchy, withException
as its most common subclass for handling errors in programs.- Common built-in exceptions like
ValueError
,TypeError
,IndexError
, andKeyError
inherit fromException
and are raised in different situations. - You can catch multiple exceptions either by combining them in a single
except
block or by using multipleexcept
blocks. - You can create custom exceptions by inheriting from the
Exception
class when you need more specific error handling in your programs. - Python’s exception hierarchy helps organize and categorize errors, allowing you to handle specific types of exceptions in a more controlled manner.
By understanding Python’s exception hierarchy, you can write more robust code that handles different types of errors effectively, and you can extend this system by defining your own exceptions for specialized use cases.