On this page
Python Error Handling and Exceptions
Basic Exception Handling (try, except, finally)
Python uses try, except, and finally blocks to handle errors and exceptions gracefully, allowing your program to continue running even when an error occurs.
tryBlock: Contains the code that might raise an exception.exceptBlock: Catches and handles the exception if it occurs.finallyBlock: Contains code that will always execute, whether an exception occurred or not.
Example:
try:
x = 10 / 0 # This will raise a ZeroDivisionError
except ZeroDivisionError:
print("You can't divide by zero!")
finally:
print("This will run no matter what.")
Custom Exceptions
You can create your own exceptions by defining a new class that inherits from the built-in Exception class. Custom exceptions are useful when you need to handle specific errors in your application.
Example:
class CustomError(Exception):
pass
def check_value(value):
if value < 0:
raise CustomError("Value cannot be negative!")
try:
check_value(-1)
except CustomError as e:
print(e)
Debugging Techniques
Debugging is the process of identifying and fixing errors in your code. Python provides several tools and techniques for debugging.
- Using Print Statements: One of the simplest ways to debug is by adding
printstatements to check the values of variables at different points in your code.
x = 5
print(f"x before loop: {x}")
for i in range(10):
x += i
print(f"x after adding {i}: {x}")
- Using
assertStatements: Theassertstatement tests if a condition is true. If it is not, the program will raise anAssertionError.
def divide(a, b):
assert b != 0, "Division by zero is not allowed!"
return a / b
- Using a Debugger: Python’s built-in
pdbmodule allows you to set breakpoints, step through your code, and inspect variables interactively.
import pdb
pdb.set_trace()
- Using IDE Debugging Tools: Many IDEs (e.g., PyCharm, Visual Studio Code) provide advanced debugging tools that allow you to set breakpoints, watch variables, and step through your code line by line.
Handling Multiple Exception Types
try:
result = int(user_input) / divisor
except (ValueError, ZeroDivisionError) as e:
print(f"Invalid operation: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
raise # re-raise after logging
else and finally Clauses
try:
file = open('data.txt')
except FileNotFoundError:
print('File missing')
else:
print(file.read()) # runs only if no exception
file.close()
finally:
print('Cleanup always runs')
Exception Chaining
Preserve the original cause when wrapping errors:
try:
config = json.loads(raw)
except json.JSONDecodeError as e:
raise ConfigError('Invalid config file') from e
Logging Exceptions
import logging
logger = logging.getLogger(__name__)
try:
process_order(order_id)
except OrderError as e:
logger.exception('Order %s failed', order_id)
raise
logger.exception() automatically includes the stack trace.
When to Use Exceptions vs Return Values
| Situation | Approach |
|---|---|
| Expected failure (file not found) | Return None or Result type |
| Programming bug (index out of range) | Let exception propagate |
| User input validation | Raise ValueError with clear message |
| API errors | Custom exception with status code |