Mastering Exception Handling in Python: Failing Gracefully

Introduction to Exception Handling
Even the best-written code can run into unexpected situations—a missing file, a lost internet connection, or an invalid user input. In Python, these runtime disruptions are called Exceptions.
In this tutorial, we will explore:
- The difference between Syntax Errors and Exceptions.
- How to use
try,except,else, andfinallyblocks. - How to raise your own exceptions.
- Creating Custom Exception classes.
Errors vs. Exceptions
Syntax Errors
These occur when Python cannot parse your code because it doesn't follow the language rules. These are caught before the program runs.
1for i in range(10) # Missing colon!
2 print(i)
3# Output: SyntaxError: invalid syntaxExceptions
These are errors detected during execution. The code might be syntactically correct, but something goes wrong while it's running.
1print(1 / 0)
2# Output: ZeroDivisionError: division by zero
3
4print("Number: " + 5)
5# Output: TypeError: can only concatenate str (not "int") to strThe Exception Handling Block
To prevent your program from crashing, you wrap risky code in a try block and handle potential errors in an except block.
1. The try and except Blocks
The try block contains the code that might fail. If an error occurs, Python jumps to the except block.
1try:
2 number = int(input("Enter a number: "))
3 print(10 / number)
4except ZeroDivisionError:
5 print("Error: You cannot divide by zero!")
6except ValueError:
7 print("Error: Please enter a valid integer.")2. The else Block (Optional)
The else block runs only if no exceptions were raised in the try block.
1try:
2 print("Trying something safe...")
3except:
4 print("Something went wrong.")
5else:
6 print("Success! No errors occurred.")3. The finally Block (Optional)
The finally block always runs, regardless of whether an exception occurred. It's perfect for cleanup tasks like closing files or database connections.
1try:
2 f = open("data.txt", "r")
3 # Perform operations
4except FileNotFoundError:
5 print("File not found!")
6finally:
7 print("Cleaning up resources...")
8 # f.close() would go hereRaising Exceptions
You can manually trigger an exception using the raise keyword. This is useful for enforcing business logic.
1def set_age(age):
2 if age < 0:
3 raise ValueError("Age cannot be negative!")
4 print(f"Age set to {age}")
5
6try:
7 set_age(-5)
8except ValueError as e:
9 print(f"Caught an error: {e}")Creating Custom Exceptions
Sometimes, built-in exceptions like ValueError aren't specific enough. You can create your own by inheriting from the base Exception class.
1class InsufficientFundsError(Exception):
2 """Raised when a bank account balance is too low."""
3 def __init__(self, balance, amount):
4 self.message = f"Balance ${balance} is less than withdrawal amount ${amount}"
5 super().__init__(self.message)
6
7# Usage
8raise InsufficientFundsError(100, 500)Pro-Tip: Hierarchy Matters
When using multiple `except` blocks, always catch specific exceptions (like `ZeroDivisionError`) before general ones (like `Exception`). Python evaluates them from top to bottom!
Conclusion
Exception handling is the difference between a fragile script and a professional application. By mastering these blocks, you ensure your software remains stable and user-friendly even when things go wrong.
Resources
Check out the [official Python documentation](https://docs.python.org/3/library/exceptions.html) for a full list of built-in exceptions.
