Skip to content

Python Exception Handling: Detailed Overview and Examples

Exception handling in Python is a mechanism to handle errors and exceptional conditions that occur during the execution of a program. It allows you to gracefully manage errors, ensuring that your program can continue running or terminate in a controlled manner.

Basic Concepts

What is an Exception?

An exception is an event that disrupts the normal flow of a program. It typically indicates an error condition or an unusual situation. Examples include division by zero, file not found, or invalid user input.

Try and Except Block

The core structure for handling exceptions is the try and except block.

Example: Basic Exception Handling

try:
    result = 10 / 0
except ZeroDivisionError:
    print('You cannot divide by zero!')

Multiple Exceptions

Handling Multiple Exceptions

You can handle multiple exceptions using multiple except blocks.

Example: Handling Multiple Exceptions

try:
    result = 10 / 0
except ZeroDivisionError:
    print('You cannot divide by zero!')
except FileNotFoundError:
    print('The file was not found!')

Handling Multiple Exceptions in a Single Block

You can also handle multiple exceptions in a single except block.

Example: Single Block for Multiple Exceptions

try:
    result = 10 / 0
except (ZeroDivisionError, FileNotFoundError) as e:
    print(f'An error occurred: {e}')

The else and finally Clauses

Using the else Clause

The else clause runs if the try block did not raise an exception.

Example: Using else

try:
    result = 10 / 2
except ZeroDivisionError:
    print('You cannot divide by zero!')
else:
    print('Division successful!')
    print(f'Result is: {result}')

Using the finally Clause

The finally clause runs regardless of whether an exception was raised or not. It is often used for cleanup actions.

Example: Using finally

try:
    file = open('example.txt', 'r')
    data = file.read()
except FileNotFoundError:
    print('The file was not found!')
finally:
    file.close()
    print('File closed.')

Raising Exceptions

Raising Exceptions Manually

You can raise exceptions manually using the raise keyword.

Example: Raising Exceptions

def divide(a, b):
    if b == 0:
        raise ValueError('The divisor cannot be zero.')
    return a / b

try:
    result = divide(10, 0)
except ValueError as e:
    print(e)

Custom Exceptions

Creating Custom Exceptions

You can define your own exceptions by subclassing the built-in Exception class.

Example: Custom Exception

class CustomError(Exception):
    pass

def do_something():
    raise CustomError('This is a custom error.')

try:
    do_something()
except CustomError as e:
    print(e)

Exception Chaining

Using raise to Re-raise Exceptions

You can re-raise the original exception in an except block to preserve the original traceback.

Example: Exception Chaining

def function1():
    try:
        raise ValueError('An error occurred in function1.')
    except ValueError:
        print('Handling error in function1.')
        raise

try:
    function1()
except ValueError:
    print('Caught an exception in the outer block.')

Practical Examples

Example 1: Handling User Input

while True:
    try:
        number = int(input('Enter a number: '))
        print(f'You entered: {number}')
        break
    except ValueError:
        print('Invalid input! Please enter a valid integer.')

Example 2: File Operations with Exception Handling

filename = 'data.txt'

try:
    with open(filename, 'r') as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print(f'The file {filename} was not found.')
except IOError:
    print('An I/O error occurred while reading the file.')

Example 3: Handling Multiple Errors

def process_data(data):
    try:
        # Simulate processing
        if not data:
            raise ValueError('Data is empty.')
        result = int(data) / 2
    except ValueError as ve:
        print(f'ValueError: {ve}')
    except ZeroDivisionError:
        print('ZeroDivisionError occurred.')
    else:
        print(f'Processing result: {result}')
    finally:
        print('Processing complete.')

process_data('10')
process_data('')

Conclusion

Python's exception handling provides a robust mechanism for managing errors and exceptional conditions that arise during program execution. By using try, except, else, and finally blocks, you can handle errors gracefully, ensuring that your program can deal with unexpected situations effectively. Custom exceptions and exception chaining further enhance your ability to manage and debug complex error scenarios.