Middle
221
How do nested exceptions work in Python?
Answer from AI
sobes.tech AI
Nested exceptions, also known as exception chaining, allow preserving information about a previous exception when a new one occurs. This is useful for debugging and understanding the cause of an error.
In Python 3, by default, when a new exception occurs inside an except or finally block, the original exception is automatically linked to the new one.
This link is stored in the __cause__ attribute of the new exception.
Explicit linking can be done using the raise from keyword.
# Example of automatic linking
def divide(a, b):
try:
return a / b
except TypeError:
# During handling of TypeError, another exception may occur
# The original exception (TypeError) will be linked to the new one
raise ValueError("Invalid operand types")
try:
divide("a", 0)
except ValueError as e:
# e.__cause__ will contain the TypeError
print(f"An error occurred: {e}")
if e.__cause__:
print(f"Caused by: {e.__cause__}")
print("-" * 20)
# Example of explicit linking with raise from
class CustomError(Exception):
pass
def tricky_function():
try:
# Attempting division by zero, raises ZeroDivisionError
result = 1 / 0
except ZeroDivisionError as original_exc:
# Create a new exception and link it with the original
raise CustomError("Error during calculation") from original_exc
try:
tricky_function()
except CustomError as e:
# e.__cause__ will contain ZeroDivisionError
print(f"An error occurred: {e}")
if e.__cause__:
print(f"Caused by: {e.__cause__}")
print("-" * 20)
# Suppressing linking with raise ... from None
try:
try:
# Original exception
raise ValueError("Original error")
except ValueError:
# During handling of ValueError, another exception occurs,
# but linking is suppressed
raise TypeError("New error") from None
except TypeError as e:
# e.__cause__ will be None
print(f"An error occurred: {e}")
if e.__cause__ is None:
print("Cause not specified.")
The raise statement without arguments re-raises the last exception.
# Example of re-raising an exception
def process_data(data):
try:
# Suppose something might go wrong here
if not data:
raise ValueError("No data")
print("Data processed")
except ValueError:
print("Caught ValueError")
# Re-raise the same exception
raise
try:
process_data("")
except ValueError as e:
print(f"Caught re-raised exception: {e}")
Nested exceptions improve the readability of error tracebacks and help quickly locate the root cause of the problem.