Understanding try and except in Python

In Python, the try and except statements are used to handle errors and exceptions gracefully. This is very useful when you want your program to keep running even if something goes wrong.

How try and except Work

  1. try Block:
    • The code that might cause an error is put inside the try block.
    • Python tries to execute this code.
  2. except Block:
    • If an error occurs in the try block, the execution jumps to the except block.
    • You can specify the type of error you want to handle.

Example: Counting Character Frequency in a File

Let’s look at an example that reads a file does something with it. We’ll use try and except to handle any errors that might occur when opening the file.

def character_frequency(filename):
    """Counts the frequency of each character in the given file."""
    # First, try to open the file
    try:
        f = open(filename)
    except OSError:
        return None  # Return None if the file cannot be opened

    # Now, process the file

Raising Errors in Python

In Python, you can raise (or trigger) errors intentionally using the raise statement. This is useful when you want to raise errors if certain conditions arise. This approach can help in debugging.

Why Raise Errors?

  • Input Validation: Ensure that the input to a function is valid.
  • Preventing Illegal Operations: Stop the program from performing operations that aren’t allowed.
  • Custom Error Messages: Provide clear messages to help understand what went wrong.

How to Raise Errors

You can raise built-in exceptions or define your own custom exceptions. Here’s how:

Raising Built-in Exceptions

Python has several built-in exceptions like ValueError, TypeError, IndexError, etc. You can raise these using the raise statement.

Example: Raising a ValueError

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

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

In this example:

  • The function divide raises a ValueError if the denominator is zero.
  • The try block catches the error and prints the error message.

Custom Exceptions

You can define your own exceptions by creating a class that inherits from the Exception class.

Example: Custom Exception

class NegativeNumberError(Exception):
    pass

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

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

In this example:

  • NegativeNumberError is a custom exception.
  • The function check_positive raises NegativeNumberError if the input is negative.
  • The try block catches the error and prints the message.

Common Use Cases

  1. Validating Function Arguments

    def sqrt(x):
        if x < 0:
            raise ValueError("Cannot compute the square root of a negative number.")
        return x ** 0.5
    
    try:
        print(sqrt(-9))
    except ValueError as e:
        print(e)
    
  2. Handling Invalid States

    def withdraw(amount, balance):
        if amount > balance:
            raise RuntimeError("Insufficient funds.")
        return balance - amount
    
    try:
        print(withdraw(100, 50))
    except RuntimeError as e:
        print(e)
    

Summary

  • Raising Errors: Use the raise statement to trigger exceptions.
  • Built-in Exceptions: Raise common errors like ValueError and TypeError.
  • Custom Exceptions: Create custom error types for specific situations.

assert statements