Raising & Chaining Exceptions
In professional Python code, you don’t just wait for errors to happen; you raise them yourself to enforce business logic. If a user enters an age of -5, Python doesn’t care, but your application should.
Using the raise keyword allows you to turn logical failures into standard Python exceptions that can be handled gracefully by other parts of your system.
1. The raise Keyword
Section titled “1. The raise Keyword”You can trigger any built-in or custom exception using raise.
def set_temperature(celsius): if celsius < -273.15: raise ValueError("Temperature below absolute zero is impossible!") return celsius
try: set_temperature(-300)except ValueError as e: print(f"Validation Failed: {e}")2. Exception Chaining: from
Section titled “2. Exception Chaining: from”Sometimes you want to catch one exception and raise a different, more descriptive one. However, you don’t want to lose the original error information (the “Root Cause”).
Implicit Chaining
Section titled “Implicit Chaining”If you raise an exception inside an except block, Python automatically tracks the “Cause.”
Explicit Chaining (from)
Section titled “Explicit Chaining (from)”You can use the from keyword to link exceptions.
def get_config(): try: with open("config.json") as f: return f.read() except FileNotFoundError as e: # We wrap the FileNotFoundError in a custom ApplicationError raise RuntimeError("Application failed to start") from eOutput Traceback:
FileNotFoundError: [Errno 2] No such file or directory: 'config.json'
The above exception was the direct cause of the following exception:
RuntimeError: Application failed to startSuppressing the Cause (from None)
Section titled “Suppressing the Cause (from None)”If the original error is sensitive (e.g., contains a database password) or irrelevant, you can hide it.
raise ValueError("Invalid credentials") from None3. Custom Exception Hierarchies
Section titled “3. Custom Exception Hierarchies”For large applications, you should create your own exception classes. This allows users of your code to catch your errors specifically without catching every other generic error.
class AppError(Exception): """Base class for all errors in this app.""" pass
class DatabaseError(AppError): """Errors related to database connectivity.""" pass
class AuthError(AppError): """Errors related to user login.""" pass
# You can now catch all app errors at once,# or just specific ones.try: login_user()except AppError: # This catches both DatabaseError and AuthError show_friendly_message()4. Under the Hood: The Traceback Object
Section titled “4. Under the Hood: The Traceback Object”When an exception is raised, Python creates a Traceback Object (__traceback__). This object is a linked list of every function call that was currently active on the stack.
When you raise an exception, Python starts “unwinding” the stack, looking for a matching except block. If it doesn’t find one, it prints the traceback, showing you the exact file and line number of every step that led to the crash.