Exception Handling in Python

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.

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:

ExceptionDescription
ZeroDivisionErrorDivision by zero
ValueErrorInvalid value
TypeErrorType mismatch
IndexErrorList index out of range
KeyErrorDictionary key not found
AttributeErrorAttribute not found
FileNotFoundErrorFile does not exist
ImportErrorImport statement fails
NameErrorUsing 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 or BaseException
  • 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

  1. Write a program that reads an integer and catches ValueError if input is invalid.
  2. Create a function that raises TypeError if input is not a list.
  3. Implement custom exception for age validation.
  4. Simulate a division operation that gracefully handles ZeroDivisionError.
  5. Wrap file reading in try-except and handle missing file scenario.
  6. 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.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top