Python
  • Intro.
  • Catalogue
  • Chapter 1: Introduction to Python
  • Chapter 2: Python Syntax and Fundamentals
    • Chapter: Variables and Data Types in Python
  • Chapter 3: Control Flow
  • Chapter 4: Functions
  • Chapter 5: Data Structures
  • Chapter 6: Object-Oriented Programming (OOP)
  • Chapter 7: Modules and Packages
  • Chapter 8: File Handling
  • Chapter 9: Error and Exception Handling
  • Chapter 10: Working with Databases
  • Chapter 11: Iterators and Generators
  • Chapter 12: Decorators and Context Managers
  • Chapter 13: Concurrency and Parallelism
  • Chapter 14: Testing and Debugging
  • Chapter 15: Web Development with Python
  • Chapter 16: Data Science and Machine Learning with Python
  • Chapter 17: Working with APIs
  • Chapter 18: Automation with Python
  • Chapter 19: Python and Cloud/DevOps
  • Chapter 20: Python and IoT
  • Appendices
Powered by GitBook
On this page

Chapter 9: Error and Exception Handling

Errors and exceptions are inevitable in programming. Python provides a robust mechanism for handling errors gracefully to ensure programs can recover and continue execution where possible.

Types of Errors

  1. Syntax Errors:

    • Occur when the code violates Python’s grammar rules.

    • Example:

      print("Hello")  # Correct
      print("Hello"    # SyntaxError: unexpected EOF while parsing
  2. Runtime Errors:

    • Occur during the execution of a program.

    • Example:

      result = 10 / 0  # ZeroDivisionError
  3. Logical Errors:

    • Errors in the program’s logic that produce incorrect results without causing crashes.

    • Example:

      # Intended to calculate the average
      total = 100
      count = 0
      average = total / count  # ZeroDivisionError

Handling Exceptions

Python uses try...except blocks to handle exceptions.

Syntax:

try:
    # Code that might raise an exception
except ExceptionType:
    # Code to handle the exception
finally:
    # Code that executes regardless of an exception (optional)

Example:

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 number.")
finally:
    print("Execution completed.")

The else Clause

The else block executes if no exceptions are raised in the try block.

Example:

try:
    num = int(input("Enter a number: "))
    print("You entered:", num)
except ValueError:
    print("That’s not a valid number.")
else:
    print("Success! No errors occurred.")

Raising Exceptions

Use the raise keyword to generate exceptions intentionally.

Example:

def validate_age(age):
    if age < 0:
        raise ValueError("Age cannot be negative.")
    print("Valid age.")

try:
    validate_age(-5)
except ValueError as e:
    print("Error:", e)

Creating Custom Exceptions

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

Example:

class NegativeNumberError(Exception):
    def __init__(self, value):
        self.value = value

try:
    num = int(input("Enter a positive number: "))
    if num < 0:
        raise NegativeNumberError(num)
except NegativeNumberError as e:
    print(f"Negative numbers are not allowed: {e.value}")

Common Built-in Exceptions

Exception

Description

ValueError

Raised when a function receives an invalid argument.

TypeError

Raised when an operation is performed on an inappropriate type.

ZeroDivisionError

Raised when dividing by zero.

KeyError

Raised when a key is not found in a dictionary.

IndexError

Raised when an index is out of range.

FileNotFoundError

Raised when a file operation fails because the file doesn’t exist.

Example:

try:
    my_dict = {"name": "Alice"}
    print(my_dict["age"])
except KeyError:
    print("Key not found.")

Logging Exceptions

Use the logging module to record errors and exceptions for debugging and analysis.

Example:

import logging

logging.basicConfig(filename="app.log", level=logging.ERROR)

try:
    result = 10 / 0
except ZeroDivisionError as e:
    logging.error("Exception occurred", exc_info=True)

Exercises

Exercise 1:

Write a program to take two numbers as input and perform division. Handle ZeroDivisionError and ValueError exceptions.

Solution:

try:
    num1 = int(input("Enter numerator: "))
    num2 = int(input("Enter denominator: "))
    result = num1 / num2
    print("Result:", result)
except ZeroDivisionError:
    print("Error: Cannot divide by zero.")
except ValueError:
    print("Error: Invalid input. Please enter numbers only.")

Exercise 2:

Create a custom exception OutOfRangeError that is raised when a number is not between 1 and 100.

Solution:

class OutOfRangeError(Exception):
    pass

try:
    num = int(input("Enter a number between 1 and 100: "))
    if num < 1 or num > 100:
        raise OutOfRangeError("Number out of range.")
    print("Valid number.")
except OutOfRangeError as e:
    print("Error:", e)

Exercise 3:

Write a program that logs errors to a file instead of printing them to the console.

Solution:

import logging

logging.basicConfig(filename="errors.log", level=logging.ERROR)

try:
    num = int(input("Enter a number: "))
    result = 10 / num
except Exception as e:
    logging.error("Error occurred: %s", e)
    print("An error occurred. Check errors.log for details.")

Best Practices

  1. Use specific exception types instead of a generic except clause.

  2. Keep the try block small and focused.

  3. Log exceptions for debugging and maintenance.

  4. Avoid using exceptions for normal control flow.

  5. Use custom exceptions to represent specific error cases in your application.

In the next chapter, we will explore working with databases using Python, including basic CRUD operations and interacting with sqlite3.

PreviousChapter 8: File HandlingNextChapter 10: Working with Databases

Last updated 5 months ago