Exception handling ( Error handling ) is an essential part of writing robust and reliable programs. In Python, exceptions provide a structured and readable way to handle errors that may occur during runtime. Instead of crashing, programs can catch exceptions and decide how to respond — such as showing a message, logging an error, or attempting recovery.
In this chapter, we’ll cover Python’s exception-handling framework in depth — including try
, except
, else
, and finally
blocks, built-in exceptions, custom exception classes, exception hierarchy, debugging techniques, and best practices.
Table of Contents
1. What Is an Exception?
An exception is an event that disrupts the normal flow of a program. It typically occurs when Python encounters an error during execution.
Common Exception Scenarios:
- Dividing by zero
- Accessing an undefined variable
- File not found
- Type mismatch
- Index out of range
2. Basic Exception Handling with try
and except
Syntax:
try:
# risky code
except ExceptionType:
# error handling code
Example:
try:
x = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero.")
3. Catching Multiple Exceptions
You can handle multiple exceptions using multiple except
blocks.
try:
a = int(input("Enter number: "))
b = 10 / a
except ValueError:
print("Invalid input. Please enter a number.")
except ZeroDivisionError:
print("You cannot divide by zero.")
Or combine them:
except (ValueError, ZeroDivisionError) as e:
print(f"Error occurred: {e}")
4. Using else
Block
Executes only if no exception occurs.
try:
x = int(input("Enter a number: "))
except ValueError:
print("Not a number")
else:
print(f"You entered: {x}")
5. Using finally
Block
Executes regardless of whether an exception occurs.
try:
f = open("data.txt")
content = f.read()
except FileNotFoundError:
print("File not found.")
finally:
print("Closing the file.")
Use finally
to release resources (files, network, memory).
6. Built-in Exceptions in Python
Some common built-in exceptions:
Exception | Description |
---|---|
ZeroDivisionError | Division by zero |
ValueError | Invalid value |
TypeError | Type mismatch |
IndexError | List index out of range |
KeyError | Dictionary key not found |
AttributeError | Attribute not found |
FileNotFoundError | File does not exist |
ImportError | Import statement fails |
NameError | Using an undefined variable |
7. The Exception Hierarchy
All exceptions inherit from the BaseException
class.
BaseException
├── SystemExit
├── KeyboardInterrupt
└── Exception
├── ArithmeticError
├── LookupError
└── RuntimeError
This allows catching all exceptions using except Exception:
8. Accessing Exception Details
Use as
keyword to capture exception object.
try:
x = 1 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")
You can log or inspect this object for debugging.
9. Raising Exceptions with raise
You can manually raise exceptions.
age = -5
if age < 0:
raise ValueError("Age cannot be negative")
10. Creating Custom Exceptions
You can define your own exceptions by subclassing Exception
.
class InvalidAgeError(Exception):
pass
def check_age(age):
if age < 0:
raise InvalidAgeError("Age must be non-negative")
With Custom Message:
class MyError(Exception):
def __init__(self, message):
self.message = message
super().__init__(self.message)
11. Re-raising Exceptions
Use raise
inside an except
block to rethrow the exception.
try:
x = 1 / 0
except ZeroDivisionError:
print("Handling...")
raise
12. Nested Exception Handling
You can nest try
blocks.
try:
try:
x = int("abc")
except ValueError:
print("Inner block error")
except:
print("Outer block error")
13. Logging Exceptions
Use logging
module for professional applications.
import logging
logging.basicConfig(level=logging.ERROR)
try:
1 / 0
except ZeroDivisionError as e:
logging.error("Exception occurred", exc_info=True)
14. Best Practices
- Be specific with exception types
- Avoid catching broad
Exception
orBaseException
- Always clean up resources with
finally
- Log exceptions in production applications
- Avoid silent failures (e.g., empty
except:
)
15. Real-World Use Cases
- Web apps: Handle user input errors
- File processing: Handle missing or corrupt files
- APIs: Return meaningful error responses
- Data validation: Ensure clean data
- Security: Catch and log suspicious activity
16. Exercises
- Write a program that reads an integer and catches
ValueError
if input is invalid. - Create a function that raises
TypeError
if input is not a list. - Implement custom exception for age validation.
- Simulate a division operation that gracefully handles
ZeroDivisionError
. - Wrap file reading in try-except and handle missing file scenario.
- Log exception details to a file using
logging
.
17. Summary
Exception handling makes your Python programs more robust and user-friendly by managing errors gracefully. From basic try-except
blocks to custom exception classes and logging strategies, mastering exception handling is vital for professional software development.
✅ Next Chapter: Object-Oriented Programming – Learn the foundations of classes, objects, inheritance, and polymorphism in Python.