🀌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.

Different types of exceptions in python:

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.

Difference between Syntax Error and Exceptions

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

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

a. The try and except Blocks

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:

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:

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.

b. Handling Multiple Exceptions

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

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:

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

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:

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.

d. Raising Exceptions

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:

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

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:

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:

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:

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.

Last updated