› Module 9: Exception Handling › 9.2 Raising & Creating Custom Exceptions
M O D U L E

Module 9: Exception Handling

Catching and responding to runtime errors gracefully, instead of letting an unexpected problem crash the entire program.

9.1 try, except, else, and finally

Code that might fail is placed inside a try block. If an exception actually occurs, control immediately jumps to a matching except block — you can target a specific exception type, or use a broad Exception to catch nearly anything.

An optional else block runs only when the try block completed with absolutely no exception, which is useful for keeping "this only happens on success" logic cleanly separated from the risky code itself.

Finally, a finally block always runs — whether an exception happened or not — making it the standard, reliable place to put cleanup code, such as closing a file or a network connection.

A Complete try/except/else/finally Example

# A COMPLETE TRY/EXCEPT/ELSE/FINALLY
try:
    result = 10 / int(input("Divide by: "))
except ZeroDivisionError:
    print("Cannot divide by zero")
except ValueError:
    print("Please enter a number")
else:
    print(f"Result: {result}")
finally:
    print("Done")
try: risky code error except Err: handle it else: runs only if NO exception occurred finally: always runs (cleanup)
Figure 9.1 — try attempts risky code; except handles failure; else runs only on success; finally always runs.

9.2 Raising & Creating Custom Exceptions

The raise statement lets your own code deliberately trigger an exception whenever something is wrong: raise ValueError("age cannot be negative").

Beyond Python's built-in exception types, you can define your own by inheriting from the built-in Exception class, giving your codebase clear, self-documenting, domain-specific error types instead of leaning only on generic built-ins.

A Custom Exception (from the Guide)

# A CUSTOM EXCEPTION
class InsufficientFundsError(Exception):
    pass

def withdraw(balance, amount):
    if amount > balance:
        raise InsufficientFundsError("Not enough balance")
    return balance - amount

try:
    withdraw(100, 250)
except InsufficientFundsError as e:
    print(f"Transaction failed: {e}")

💡 Pythonic Design: EAFP vs LBYL

Python culture strongly embraces EAFP ("Easier to Ask for Forgiveness than Permission") over LBYL ("Look Before You Leap"):

# LBYL (Defensive style common in C):
if key in my_dict:
    val = my_dict[key]

# EAFP (Pythonic style):
try:
    val = my_dict[key]
except KeyError:
    val = None

EAFP avoids race conditions in multi-threaded environments and avoids double hash lookups!

MODULE COMPREHENSIVE QUIZ

Module 9 Final Quiz

Test your understanding across all 2 topics of this module with interview-grade questions, tricky edge cases, and code output predictions.

Take Module 9 Final Quiz →
Yukti Mascot