Basic Python: 10. Exception Handling
Tags: python, beginners, programming, tutorial
Published: 2023-08-30 14:36:14

In the world of programming, errors are inevitable. However, Python provides a robust mechanism for dealing with errors and preventing your program from crashing. This mechanism is called **exception handling**. In this blog post, we will explore the concepts of exception handling in Python, how to catch and handle different types of exceptions, and best practices to ensure your code remains robust and resilient. Let's dive in!

### Table of Contents

1. **Introduction to Exception Handling**
2. **Basic Syntax of try-except**
3. **Catching Specific Exceptions**
4. **Handling Multiple Exceptions**
5. **Using `else` and `finally`**
6. **Raising Custom Exceptions**
7. **Common Built-in Exceptions**
8. **Best Practices for Exception Handling**
9. **Real-world Example: File Handling**

### 1. Introduction to Exception Handling

An exception in Python is an event that occurs during the execution of a program and disrupts its normal flow. Exception handling allows you to gracefully deal with these unexpected situations and prevent your program from crashing.

### 2. Basic Syntax of try-except

The core of exception handling in Python is the `try` and `except` blocks. Here's a simple example:

```python
try:
    # Code that might raise an exception
except ExceptionType:
    # Code to handle the exception
```

For instance:

```python
try:
    num = int(input("Enter a number: "))
    result = 10 / num
    print("Result:", result)
except ZeroDivisionError:
    print("Cannot divide by zero!")
except ValueError:
    print("Invalid input. Please enter a valid number.")
```

### 3. Catching Specific Exceptions

You can catch specific exceptions to handle different types of errors more precisely:

```python
try:
    # Code that might raise an exception
except SpecificException:
    # Code to handle the specific exception
```

### 4. Handling Multiple Exceptions

You can handle multiple exceptions in a single `try` block:

```python
try:
    # Code that might raise an exception
except (ExceptionType1, ExceptionType2):
    # Code to handle the exceptions
```

### 5. Using `else` and `finally`

The `else` block is executed when no exception occurs, and the `finally` block is always executed, whether an exception is raised or not.

```python
try:
    # Code that might raise an exception
except SpecificException:
    # Code to handle the exception
else:
    # Code to execute when no exception occurs
finally:
    # Code that always executes
```

### 6. Raising Custom Exceptions

You can raise your own exceptions using the `raise` statement. This is useful when you want to handle specific scenarios in your code.

```python
def validate_age(age):
    if age < 0:
        raise ValueError("Age cannot be negative")

try:
    user_age = int(input("Enter your age: "))
    validate_age(user_age)
except ValueError as ve:
    print(ve)
```

### 7. Common Built-in Exceptions

Python provides a variety of built-in exceptions that cover different error scenarios, such as `TypeError`, `IndexError`, `KeyError`, and more.

### 8. Best Practices for Exception Handling

- **Be Specific**: Catch specific exceptions rather than using a generic `except` block.
- **Keep it Simple**: Avoid excessive nesting of `try` and `except` blocks.
- **Document Your Code**: Use comments or docstrings to explain the purpose of your exception handling.
- **Log Exceptions**: Use the `logging` module to log exceptions for debugging.
- **Test Exception Cases**: Write test cases to ensure your exception handling works as intended.

### 9. Real-world Example: File Handling

Exception handling is crucial in file operations, where unforeseen issues can occur. Let's look at an example of reading from a file:

Consider you have a file named `example.txt` with the following content:

```
Hello, this is an example file.
It contains some text for demonstration.
```

Now, let's write code to read the content of this file using exception handling:

```python
file_path = "example.txt"
try:
    with open(file_path, "r") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print(f"File '{file_path}' not found")
except Exception as e:
    print(f"An error occurred: {e}")
```

In this code snippet, we first attempt to open and read the file using a `with` statement, which automatically closes the file when we're done. If the file is found, its content is read and printed. However, two exceptions are being handled:

1. **FileNotFoundError**: If the file specified by `file_path` doesn't exist, a `FileNotFoundError` will be raised. We catch this exception and print a user-friendly error message.

2. **Exception**: This is a catch-all exception that handles any other unexpected errors that might occur while trying to open and read the file. We print a generic error message along with the specific error message provided by the exception.

By using exception handling in this scenario, we can ensure that our program doesn't crash if the file is missing or if some other unexpected error occurs during the file operations.