Exception Handling in Python

 

Exception Handling in Python

Exception handling is an essential concept in Python that allows a program to handle unexpected situations or errors gracefully without crashing. It helps ensure that your code can recover from runtime issues, perform necessary clean-up operations, and provide more informative error messages to the user.

In Python, exception handling is done using the try, except, else, and finally blocks.


1. Basic Syntax of Exception Handling

Python's syntax for exception handling involves four main blocks:

  • try block: The code that might raise an exception is placed inside the try block.
  • except block: If an exception occurs in the try block, the program moves to the except block where the exception is handled.
  • else block: This block is optional. It is executed if no exception occurs in the try block.
  • finally block: This block is also optional. It runs after the try and except blocks, regardless of whether an exception occurred or not. It is typically used for clean-up operations (e.g., closing files or releasing resources).

2. Basic Example of Exception Handling

try:
    # Code that might raise an exception
    x = 10 / 0  # Division by zero will raise an exception
except ZeroDivisionError:
    print("Error: Division by zero is not allowed.")

In this example:

  • The try block contains code that attempts to divide a number by zero, which will raise a ZeroDivisionError.
  • The except block catches the ZeroDivisionError and prints a user-friendly error message.

3. Catching Multiple Exceptions

You can handle multiple exceptions by specifying more than one except block. This is useful when different errors need different handling strategies.

Example: Handling Multiple Exceptions

try:
    # Code that might raise multiple exceptions
    user_input = input("Enter a number: ")
    result = 10 / int(user_input)  # May raise ZeroDivisionError or ValueError
except ZeroDivisionError:
    print("Error: Cannot divide by zero.")
except ValueError:
    print("Error: Invalid input. Please enter a valid number.")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

In this example:

  • The except ZeroDivisionError block handles division by zero errors.
  • The except ValueError block handles invalid inputs.
  • The except Exception block is a general catch-all for any other exceptions that occur.

4. The else Block

The else block is executed only if no exception is raised in the try block. It is commonly used to run code that should only be executed if no exceptions occurred, such as printing the result of an operation.

Example: Using else

try:
    # Code that might raise an exception
    num = int(input("Enter a number: "))
    result = 10 / num
except ZeroDivisionError:
    print("Error: Cannot divide by zero.")
except ValueError:
    print("Error: Invalid input.")
else:
    print(f"The result is {result}")

In this example:

  • If no exception occurs (i.e., the user enters a valid number and it's not zero), the else block prints the result.

5. The finally Block

The finally block is executed no matter what happens in the try and except blocks. It is typically used for clean-up actions that should always be performed, such as closing files or releasing resources.

Example: Using finally

try:
    file = open("example.txt", "r")
    content = file.read()
except FileNotFoundError:
    print("Error: File not found.")
else:
    print("File read successfully.")
finally:
    file.close()  # Ensures the file is closed even if an exception occurs
    print("File closed.")

In this example:

  • The finally block ensures that the file is closed, whether an exception occurred or not.

6. Raising Exceptions

You can raise exceptions in your code using the raise keyword. This is useful when you want to enforce certain conditions or signal that something went wrong.

Example: Raising an Exception

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero.")
    return a / b

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

In this example:

  • The raise ValueError statement is used to raise an exception when division by zero is attempted.

7. Custom Exceptions

You can create your own custom exceptions by defining a new exception class that inherits from the built-in Exception class. Custom exceptions are useful when you need to raise errors specific to your application.

Example: Creating a Custom Exception

class NegativeNumberError(Exception):
    pass

def check_positive(number):
    if number < 0:
        raise NegativeNumberError("Negative numbers are not allowed.")
    return number

try:
    check_positive(-5)
except NegativeNumberError as e:
    print(e)

In this example:

  • A custom exception NegativeNumberError is defined.
  • The check_positive function raises this exception if the input is negative.

8. Best Practices for Exception Handling

  • Handle specific exceptions: Always catch specific exceptions rather than using a general except Exception. This provides better error handling and avoids masking other errors.

    try:
        # Code that might raise exceptions
    except ZeroDivisionError:
        # Handle ZeroDivisionError
    except ValueError:
        # Handle ValueError
    
  • Use the else block for code that should only run when no exceptions occur.

  • Use finally for clean-up: Always use the finally block when dealing with external resources (e.g., files, database connections).

  • Don't use try-except to control regular flow: Exception handling should be used for exceptional cases, not for regular flow control.

  • Provide useful error messages: Always provide clear and meaningful error messages so that the user (or developer) can understand what went wrong.


9. Summary of Exception Handling Concepts

  • try: Block of code that might raise an exception.
  • except: Block that catches and handles specific exceptions.
  • else: Block that runs if no exception occurs in the try block.
  • finally: Block that runs after the try and except blocks, used for cleanup operations.
  • raise: Used to explicitly raise exceptions in your code.
  • Custom exceptions: You can define your own exception classes for specific conditions.

By using exception handling in Python, you can ensure that your programs are more resilient, can recover from errors gracefully, and provide more useful feedback to users and developers.

Python

Machine Learning