Fundamentals 7 min read

The Art of Exception Handling in Python: Using raise...from

This article explains how Python's raise...from statement can be used to link exceptions, providing clear examples that demonstrate basic usage, function integration, file handling, multi‑level chaining, network errors, class methods, database queries, serialization, loops, and decorators to improve error reporting and debugging.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
The Art of Exception Handling in Python: Using raise...from

🌟 The Art of Exception Handling in Python 🌟

In Python, handling errors gracefully improves code robustness and makes debugging easier. The raise...from statement lets you raise an exception while explicitly linking it to another, creating an exception chain that conveys cause and context.

What is raise...from?

The raise statement triggers an exception. By adding from followed by another exception, you indicate that the new exception was caused by the original one, establishing a causal relationship.

Example Code

Below are ten examples illustrating how raise...from works in various scenarios. Each snippet is wrapped in a try‑except block to capture and print the exception and its cause.

Example 1: Basic usage – raise an exception and link it

try:
    raise ValueError("Something went wrong") from ZeroDivisionError("Divided by zero")
except Exception as e:
    print(f"Cause: {e.__cause__}")
    print(f"Context: {e.__context__}")
    print(f"{e}")

Example 2: Using inside a function

def risky_operation():
    try:
        result = 1 / 0
    except ZeroDivisionError as zde:
        raise ValueError("Cannot perform operation") from zde

try:
    risky_operation()
except Exception as e:
    print(f"{e} caused by {e.__cause__}")

Example 3: Handling a missing file

try:
    with open("nonexistent_file.txt") as f:
        pass
except FileNotFoundError as fnfe:
    raise IOError("Failed to read file") from fnfe

Example 4: Multi‑level exception linking

try:
    raise IndexError("List index out of range") from KeyError("Key not found")
except Exception as e:
    print(f"{e} caused by {e.__cause__}")

Example 5: Network request failure

import requests

def fetch_url(url):
    try:
        response = requests.get(url)
        response.raise_for_status()
    except requests.exceptions.HTTPError as http_err:
        raise IOError("Failed to fetch URL") from http_err

try:
    fetch_url("http://example.com/nonexistent")
except Exception as e:
    print(f"{e} caused by {e.__cause__}")

Example 6: In a class method

class CustomException(Exception):
    pass

class MyClass:
    def __init__(self):
        self.value = None
    def set_value(self, val):
        if not isinstance(val, int):
            raise TypeError("Value must be an integer") from ValueError("Invalid value type")

obj = MyClass()
try:
    obj.set_value("not an int")
except Exception as e:
    print(f"{e} caused by {e.__cause__}")

Example 7: Database query error

class DBHandler:
    def query(self, sql):
        # Simulate a database error
        raise Exception("Database error")

handler = DBHandler()
try:
    handler.query("SELECT * FROM table")
except Exception as db_err:
    raise RuntimeError("Database query failed") from db_err

Example 8: Serialization problem

import json

def serialize(data):
    try:
        return json.dumps(data)
    except TypeError as te:
        raise ValueError("Data cannot be serialized") from te

try:
    serialize({"key": object()})
except Exception as e:
    print(f"{e} caused by {e.__cause__}")

Example 9: Using in a loop

for i in range(-1, 2):
    try:
        if i < 0:
            raise ValueError("Negative number") from IndexError("Index out of bounds")
        elif i == 0:
            raise ZeroDivisionError("Divided by zero")
        else:
            print("Positive number")
    except Exception as e:
        print(f"{e} caused by {e.__cause__}")

Example 10: In a decorator

def exception_decorator(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as inner_e:
            raise RuntimeError("Function execution failed") from inner_e
    return wrapper

@exception_decorator
def decorated_function():
    raise ValueError("Decorated function error")

try:
    decorated_function()
except Exception as e:
    print(f"{e} caused by {e.__cause__}")

Run Results

The print statements in the examples output the exception messages along with their linked causes, demonstrating how raise...from builds an exception chain that aids debugging and error reporting.

Conclusion

Using raise...from lets you explicitly express causal relationships between exceptions, which is especially valuable in complex error‑handling scenarios. Mastering this feature makes Python code more robust, maintainable, and easier to debug.

💡 Tip: While raise...from enriches logs with context, avoid overusing it to prevent overly complex exception traces.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

programmingError Handlingexception-handlingraise-from
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.