Exceptions are a way to handle errors or exceptional situations that may occur during the execution of a program. When an error occurs, Python raises an exception, which can be caught and handled using exception handling mechanisms.

There are several built-in exception types that are commonly encountered when writing code. These exception types help you identify and handle specific types of errors that may occur during program execution. Here are some common exception types:

  1. ZeroDivisionError: Raised when you try to divide a number by zero.
    x = 10 / 0  # Raises ZeroDivisionError
  2. TypeError: Raised when an operation or function is applied to an object of an inappropriate type.
    x = "Hello" + 5  # Raises TypeError: can only concatenate str (not "int") to str
  3. ValueError: Raised when a function receives an argument of the correct type but an inappropriate value.
    x = int("abc")  # Raises ValueError: invalid literal for int() with base 10: 'abc'
  4. IndexError: Raised when you try to access an index that is out of range in a list or other sequence.
    numbers = [1, 2, 3]
    print(numbers[5])  # Raises IndexError: list index out of range
  5. KeyError: Raised when you try to access a dictionary key that doesn't exist.
    my_dict = {"name": "John", "age": 25}
    print(my_dict["city"])  # Raises KeyError: 'city'
  6. FileNotFoundError: Raised when a file or directory is requested but cannot be found.
    file = open("nonexistent.txt")  # Raises FileNotFoundError: [Errno 2] No such file or directory: 'nonexistent.txt'

When handling exceptions, it's important to catch specific exceptions that you expect might occur and handle them appropriately. You can use try-except blocks to catch and handle exceptions and respond to specific types of errors, enabling you to take appropriate actions or provide meaningful error messages to the user.

    x = 10 / 0  # Division by zero raises an exception
except ZeroDivisionError:
    print("Error: Division by zero is not allowed.")

In this code, we use a try-except block to handle the ZeroDivisionError exception. The code inside the try block attempts to perform a division by zero, which raises an exception. The except block catches the exception and executes the code inside it, printing an error message.

Python provides many built-in exception types for handling different types of errors. Some common exceptions include ZeroDivisionError, TypeError, ValueError, and FileNotFoundError, among others. You can also create your own custom exceptions by defining new exception classes.

In addition to the except block, you can also use an optional else block and a finally block in exception handling:

  • The else block is executed if no exceptions are raised in the try block. It is useful for code that should run only when no exceptions occur.
  • The finally block is always executed, regardless of whether an exception was raised or not. It is useful for code that should be executed regardless of the outcome.

Here's an example that demonstrates the use of else and finally blocks:

    x = int(input("Enter a number: "))
    result = 10 / x
except ValueError:
    print("Error: Invalid input. Please enter a valid number.")
except ZeroDivisionError:
    print("Error: Division by zero is not allowed.")
    print("The result is:", result)
    print("Thank you for using the program!")

In this code, we use multiple except blocks to handle different types of exceptions. The else block is executed if no exceptions occur, printing the result. The finally block is always executed, printing a thank you message.

Exception handling allows us to gracefully handle errors and control the flow of your program, even in the presence of unexpected situations. It helps you write robust and reliable code.