Exception Handling in Python (with Example)

In this tutorial, we will understand exception handling in Python with the help of examples.

When we write and execute a program in Python, we may have encountered several kinds of runtime errors, such as integer division by zero, accessing a list with an out of range index, file not found, using an object reference set to None, trying to change a non-number to an integer, etc.

When these runtime errors occur in a program, it generates unexpected output or behave abnormally. To handle this unexpected situation, Python provides an exception handling mechanism that allows us to deal with run-time errors and much more.

Exception handling is an important mechanism in Python programming that enables programmers to manage errors and unexpected situations that arise during code execution.

In this tutorial, we will deal with the following topics:

  • What is an exception in Python?
  • What is exception handling?
  • Real-time example of exception and exception handling
  • Causes of exception in the program
  • Throwing and catching an exception
  • Exception handler
  • Types of exception
  • Advantages of exception handling

What is Exception in Python?


An exception means a problem or an abnormal condition that stops a computer program from processing information normally. In Python, an exception is an object representing an error or an abnormal condition that occurs at runtime and interrupts (disrupts) the normal execution of the program.

In other words, unexpected event or errors that occur during execution and interrupt the normal execution of the program are called exception in Python. It can be identified only at runtime. Therefore, it is also called runtime errors that are thrown as exceptions in the program.

Here’s an example of how an exception can occur in the Python program:

# Division by zero - causing an exception named ZeroDivisionError.
numerator = 10
denominator = 0
result = numerator / denominator  # Attempting division by zero
print("Result:", result)
Output:
       ZeroDivisionError: division by zero

In this code snippet, the attempt to divide the numerator by denominator results in an exception error named ZeroDivisionError, since division by zero is not permissible in Python. All the exceptions occur only at runtime. Errors that occur at compile-time are called syntax errors, while errors that occur during execution are called exceptions.

Exception Handling in Python


The process of handling an exception to maintain the normal flow of the program is called exception handling. In other words, the mechanism of handling unexpected errors in a program is called exception handling in Python.

It is a powerful mechanism or technique to handle runtime errors such as ZeroDivisionError, ImportError, IOError, etc. so that the normal execution of the program can be maintained. Let us understand the meaning of an exception and exception handling with real-time example to be more clear.

Realtime Example of Exception and Exception Handling

Assume that a person is traveling by car from Dhanbad to Kolkata. After traveling mid-distance, the tire of his car has punctured. This unexpected or unwanted event is nothing but an exception.

However, the car owner always keeps an extra tire as an alternative on a long-distance journey. He altered the punctured tire with a new tire. After changing the tire, he continues the rest of the journey. This alternative way is called exception handling.

Similarly, when we create and run a program in Python, an exception might arise due to errors in the logic or unforeseen issues in the code during runtime. In Python, an exception is an object that represents an error. We must handle this exception to maintain the normal execution of the program.

If we do not catch and handle this exception properly in the program, the Python interpreter will detect the exception in the program and immediately stops executing the current code block or the rest of the code.

Then, the interpreter will display a system-generated error message that describes the exception. It is usually a trace back, which is a list of all the function calls that led to the exception. If the exception is not handled properly by the program, the program will terminate abnormally.


Here, if you want the execution of the program to continue with the exception and the rest of the code, you should attempt to catch the exception object thrown by the error condition and then display appropriate messages for taking the corrective actions.

This task is nothing but exception handling. Thus, we use the exceptional handling technique in Python programming that enables us to handle the runtime exception gracefully and do something meaningful about it.

Let us take an example in which we will handle the exception occurring in the above code and generate a user-friendly message to the user.

# Division by zero - causing an exception named ZeroDivisionError.
numerator = 10
denominator = 0

try:
    result = numerator / denominator  # Attempting division by zero
    print("Result:", result)
except ZeroDivisionError as e:
    print("Error:", e)
    print("Division by zero is not allowed!") # user-friendly message.
Output:
       Error: division by zero
       Division by zero is not allowed!

In this code snippet, the attempt to divide the numerator by denominator results in a ZeroDivisionError, since division by zero is not permissible in Python. The try block attempts the division, and the except block catches the ZeroDivisionError, allowing for the handling of this exceptional scenario by printing a user-friendly error message.

Thus, handling exceptions allows programmers to not only maintain the program’s continuity but also present user-friendly error messages to the user rather than a system-generated error message, which is difficult to understand for a user.

Pictorial Representation of Exception Handling


We can visually depict the exception handling in a flowchart or diagram to illustrate its process. Here’s a simple representation:

Python exception handling diagram

(a) Start: The program execution begins here.

(b) Try Block: Code that might raise an exception is enclosed within the “try” block.

(c) Exception Occurrence: If an exception occurs within the try block, it moves to the corresponding except block.

(d) Except Block: This block catches the exception that occurred and executes the specific code to handle it.

(e) Handle Exception: Within the except block, actions like logging the error, displaying a message, or performing alternative actions take place.

(f) Continue Execution: After handling the exception, the program can continue execution or terminate based on the handling method.

(g) End: The program finishes its execution.

This visual representation highlights how exception handling allows the code to gracefully manage unexpected errors without crashing the program entirely in Python.

Causes of Exception in Program


Exceptions can occur in a Python program due to various reasons:

  • Logical errors in the program can lead to unexpected behavior or results, causing exceptions.
  • When the program asks for input from the user, and the user enters invalid input can trigger exceptions.
  • Problems related to resource availability, such as running out of memory or disk space, can cause exceptions.
  • Reading a file from a disk, but the file does not exist there, can cause exceptions.
  • Writing data to a disk, but the disk is full, or unformatted, can lead to exception.
  • When a user tries to divide an integer value by zero, an exception can take place in the program.
  • Trying to access a variable that does not define.
  • Issues with file access, such as trying to open a non-existent file or incorrect file permissions, can result in exceptions.
  • Anything unexpected or unhandled within the program’s environment or execution context can cause exceptions.

Remember that an exception generally takes place when there are logical errors, runtime errors and syntax errors in the program code.

Throwing and Catching Exception in Python


When an exception occurs or detects in a program, the Python interpreter automatically creates an exception object and throws or raises to the code that will catch it. This process is called throwing or raising an exception in Python. In simple words, the act of generating an exception is called throwing an exception.

The created exception object contains information about the type of exception, the context in which it occurred, and any associated error messages. Once the exception object is created, the interpreter then propagates it through the program’s call stack and looks for code that can handle or catch this specific type of exception.

The act of responding to an exception that has been raised during program execution is called catching an exception. The code that handles the exception is called exception handler code or simply exception handler in Python. It is responsible for receiving information about the exception/error.

When an exception is thrown or raised, the Python interpreter searches for corresponding exception handler code, typically enclosed within a try-except block. This process continues until an exception handler catches the exception. If not handled, the program will terminate.

For example, let’s consider a program in which we have a function A that calls function B, which in turn calls function C. If an exception takes place in the function C but isn’t handled in C itself, the exception propagates back through the chain of function calls. The exception object passes from the function C to function B and then to function A.

If the exception isn’t caught or handled in any of these functions, the interpreter will eventually generate an error message describing the unhandled or uncaught exception. The unhandled exception means an exception that is thrown, but never caught.

Consequently, this unhandled exception causes the program execution to abruptly halt, leading to unexpected termination or an error being displayed to the user. Look at the below an example based on it.

Example:

def function_C():
    # An intentional division by zero to trigger a ZeroDivisionError
    result = 10 / 0  # This will raise a ZeroDivisionError

def function_B():
    try:
        function_C()  # Calls function C
    except ZeroDivisionError as e:
        print("Error handled in Function B:", e)
        # Handling the exception in Function B

def function_A():
    try:
        function_B()  # Calls function B
    except ZeroDivisionError as e:
        print("Error handled in Function A:", e)
        # Handling the exception in Function A

# Calling Function A to start the chain of function calls
function_A()
Output:
       Error handled in Function B: division by zero

This example demonstrates how an unhandled exception propagates through multiple functions in Python. In this code, function_A calls function_B, which further calls function_C. The function_C intentionally attempts a division by zero, causing a ZeroDivisionError. This exception is not handled within function_C.

As a result, the exception propagates up through the chain of function calls to function_B, where it’s caught and handled within the except block. If the exception isn’t handled in function_B, it continues propagating up to function_A. If it’s still unhandled in function_A, the interpreter will display an error message and halt the program’s execution abruptly.

The critical operation which can raise an exception is placed inside the try block, while the code that handles the exceptions is written in the except block. We will understand more about try-except block with the help of various examples in the further tutorial.

Types of Exception in Python


Basically, Python supports two types of exception. They are:

  • System-defined exceptions (Built-in exceptions)
  • Custom exceptions (User-defined exceptions)

System-defined exceptions are those exceptions that are already defined by Python itself. These exceptions are also called built-in-exceptions. Some commonly used system-defined exceptions include Exception, OverflowError, ZeroDivisionError, IOError, and ArithmeticError. We will understand other built-in exceptions in the next tutorial.

User-defined exceptions (also known as custom exception) in Python are those exceptions that are created by a programmer (or user) to meet the specific needs within the application. We will understand it in more detail in the further tutorial.

Advantage of Exception Handling


Exception handling in Python offers numerous advantages that are as follows:

  • The main advantage of exception handling technique is to maintain the normal flow of the program, even in the presence of errors or exceptional situations.
  • It provides a flexible mechanism for handling various situations of errors.
  • It enables the programmers to define a user-friendly message to handle the exception.
  • The exception handling mechanism helps to separate “error-handling code” from “regular code”. This separation enhances code clarity and maintainability by isolating error-specific handling without cluttering the main code.

In this tutorial, we have explained exception handling in Python with the help of pictorial representation. Hope that you will have understood the basic concepts of exception handling and practiced example program. In the next, we will discuss types of exception in Python.
Thanks for reading!!!