> For the complete documentation index, see [llms.txt](https://python-codelivly.gitbook.io/python-mastery-from-beginner-to-expert/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://python-codelivly.gitbook.io/python-mastery-from-beginner-to-expert/advance-python/exception-handling.md).

# Exception Handling

Python Exception Handling refers to the process of anticipating, detecting, and handling exceptions that may occur during the execution of a Python program. Exceptions are events that occur during the execution of a program that disrupt the normal flow of program execution.

Python provides a robust mechanism to handle these exceptions, which includes the ability to catch and handle exceptions using try-except blocks. Exception handling allows a program to recover gracefully from errors, rather than crashing or displaying cryptic error messages to the user.

In Python, exceptions are represented as objects that are instances of a class that is derived from the built-in Exception class. When an exception is raised, the program stops executing and Python searches for an appropriate exception handler to handle the exception. If no appropriate handler is found, the program terminates and an error message is displayed.

Python exception handling is an essential programming skill that allows developers to create more robust and reliable software. &#x20;

## Different types of exceptions in python:&#x20;

There are several types of exceptions in Python. Here are some of the most common ones:

1. `SyntaxError`: raised when there is a problem with the syntax of a Python statement or block of code.
2. `NameError`: raised when an identifier (such as a variable or function name) is not found in the current namespace.
3. `TypeError`: raised when an operation or function is applied to an object of inappropriate type.
4. `ZeroDivisionError`: raised when trying to divide a number by zero.
5. `IndexError`: raised when an index is out of range.
6. `KeyError`: raised when a dictionary key is not found.
7. `ValueError`: raised when a function argument has the correct type but an inappropriate value.
8. `AttributeError`: raised when an object does not have the expected attribute.

These are just a few examples. There are many other built-in exceptions in Python, and you can also define your own custom exceptions by creating a new class that inherits from the `Exception` class.&#x20;

## Difference between Syntax Error and Exceptions&#x20;

Syntax errors and exceptions are both types of errors in Python, but they have some differences.

Syntax errors occur when the code violates the rules of the Python syntax. For example, forgetting to close a parenthesis or quotation mark, or using an undefined variable name will result in a syntax error. These errors are detected by the Python interpreter during the parsing phase, and the program cannot run until the syntax errors are fixed.

On the other hand, exceptions are errors that occur during the execution of a program, even if the code has correct syntax. They are often caused by external factors such as incorrect user input or unexpected system behavior. Examples of exceptions include ZeroDivisionError, TypeError, and ValueError. When an exception is raised, Python stops the execution of the program and looks for a handler for that particular exception.

## Handling Exceptions in Python&#x20;

In Python, exceptions can be handled using the `try`, `except`, `else`, and `finally` blocks.

### a.  The try and except Blocks&#x20;

In Python, the `try` and `except` blocks are used to handle exceptions that may occur during the execution of a program. The `try` block contains the code that may cause an exception, while the `except` block contains the code that handles the exception if it occurs.

Here is an example of using the `try` and `except` blocks:

```python
try:
    # code that may cause an exception
except ExceptionType:
    # code to handle the exception
```

In this example, `ExceptionType` is the type of exception that the `except` block is designed to handle. If an exception of that type occurs in the `try` block, the code in the `except` block will be executed.

It's important to note that if the `try` block executes successfully without any exceptions, the code in the `except` block will be skipped. If an exception occurs that is not handled by the `except` block, it will be passed up to the calling function or the interpreter, and the program will terminate with an error message.

It is also possible to include multiple `except` blocks to handle different types of exceptions:

```python
try:
    # code that may cause an exception
except ExceptionType1:
    # code to handle ExceptionType1
except ExceptionType2:
    # code to handle ExceptionType2
```

In this example, the first `except` block handles `ExceptionType1`, while the second `except` block handles `ExceptionType2`. If an exception occurs that is not handled by either `except` block, it will be passed up to the calling function or the interpreter.

### &#x20;b. Handling Multiple Exceptions&#x20;

To handle multiple exceptions, you can use multiple except blocks, each handling a specific type of exception. For example:

```python
try:
    # some code that may raise exceptions
except TypeError:
    # handle TypeError
except ValueError:
    # handle ValueError
except:
    # handle all other exceptions
```

In this example, the first except block will handle any `TypeError` exceptions raised in the try block, the second except block will handle any `ValueError` exceptions, and the third except block will handle all other exceptions (since no specific exception type is specified).

You can also handle multiple exceptions with a single except block by specifying the exceptions as a tuple:

```python
try:
    # some code that may raise exceptions
except (TypeError, ValueError):
    # handle TypeError or ValueError
except:
    # handle all other exceptions
```

In this example, the first except block will handle either `TypeError` or `ValueError` exceptions, and the second except block will handle all other exceptions.

### c. The finally Block&#x20;

### The `finally` block is a section of code that is always executed, regardless of whether an exception has been raised or not. This block is used to define cleanup actions that need to be performed, such as closing files or network connections, releasing resources, or finalizing transactions.

The syntax for the `finally` block is as follows:

```python
try:
    # Code that may raise an exception
except ExceptionType1:
    # Code to handle exception of type ExceptionType1
except ExceptionType2:
    # Code to handle exception of type ExceptionType2
finally:
    # Code that is always executed, regardless of whether an exception was raised or not
```

Here, the `finally` block is executed after the `try` and `except` blocks, regardless of whether an exception has been raised or not. If an exception is raised, the `finally` block is executed after the exception has been handled by the appropriate `except` block.

The `finally` block is often used to perform cleanup actions that are necessary to guarantee the integrity of the program, even in the event of an exception. For example, if a program opens a file and reads data from it, the `finally` block can be used to ensure that the file is properly closed, even if an exception is raised while reading the data.<br>

### d. Raising Exceptions&#x20;

In Python, you can raise an exception explicitly with the `raise` statement. This allows you to interrupt the normal flow of your program and indicate that an error has occurred. You can raise exceptions for a variety of reasons, such as invalid inputs, unexpected behavior, or errors encountered during execution.

The `raise` statement takes an exception type and an optional message as arguments. The exception type should be a subclass of the `BaseException` class, which is the parent class of all built-in exceptions in Python. You can also define your own custom exception classes by subclassing `BaseException` or any of its subclasses.

Here's an example of raising an exception:

```python
def divide(x, y):
    if y == 0:
        raise ZeroDivisionError("Cannot divide by zero")
    return x / y

try:
    result = divide(10, 0)
except ZeroDivisionError as error:
    print(error)
```

In this example, the `divide()` function raises a `ZeroDivisionError` exception if the second argument is zero. In the `try` block, we call the `divide()` function with arguments 10 and 0, which causes an exception to be raised. The `except` block catches the exception and prints the error message "Cannot divide by zero".

By raising and handling exceptions in your code, you can make your programs more robust and handle errors gracefully.

### e. Custom Exceptions&#x20;

Custom exceptions are user-defined exceptions that can be raised like any other built-in exception in Python. Custom exceptions can be created by creating a new class that inherits from the `Exception` class or any of its subclasses.

To create a custom exception, simply define a new class and inherit it from the base `Exception` class or any of its subclasses. Here's an example:

```python
class CustomException(Exception):
    pass
```

In the example above, we have defined a new class `CustomException` that inherits from the base `Exception` class. We can now use this class to raise our custom exception:

```python
try:
    # some code that may raise an exception
    raise CustomException("Something went wrong")
except CustomException as e:
    print("Error:", e)
```

In the example above, we have raised our custom exception `CustomException` with a custom error message. We have also caught this exception using the `except` block and printed the error message.

Custom exceptions can be useful when we want to provide more specific information about an error or when we want to create our own hierarchy of exceptions for a particular application or library.

## Exception Hierarchy in Python

In Python, exceptions are organized in a hierarchy of classes. At the top of the hierarchy is the base `Exception` class, and below it are more specific exception classes that inherit from the base class.

When an exception is raised, Python looks for a matching `except` block in the code. If it doesn't find one, it moves up the hierarchy and checks for a matching `except` block for the parent class. This continues until it reaches the base `Exception` class.

Here's a sample hierarchy of built-in exception classes in Python:

```lua
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- ArithmeticError
      |    +-- ZeroDivisionError
      |    +-- FloatingPointError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      +-- OSError
      |    +-- IOError
      |    +-- OSError
      |         +-- FileNotFoundError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      +-- SyntaxError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      +-- Warning
           +-- DeprecationWarning
           +-- FutureWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
```

By default, `except` blocks catch all exceptions that inherit from `Exception`. If you want to catch a specific exception class, you can specify it in the `except` block.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://python-codelivly.gitbook.io/python-mastery-from-beginner-to-expert/advance-python/exception-handling.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
