How to Catch Multiple Exceptions in Python

In this tutorial, we will learn about how to catch the multiple exceptions in Python. We will explain multiple exceptions catching mechanism and identify what we have caught. You must aware with the Python exceptional handling to dive deep into this topic.

Python throws an error when your code faces an infrequent but expected issue, like trying to open a file that doesn't exist. You should write code to handle these errors.

In contrast, a bug occurs when your code does something illogical, like making a calculation error. The bugs are needed to be fixed, not just managed. That's why debugging the code is crucial.

When your Python program encounters an error and raises an exception, it can lead to a program crash, but before that happens, Python provides a Traceback message that tells you what the problem is. Here's a simple example:

Example -

The code 10 / "One" raises a TypeError with the message "unsupported operand type(s) for /: 'int' and 'str'". Python tries to perform the division operation, but it's not possible to divide an integer

by a string, so it raises a TypeError because the operation is unsupported. To handle exceptions and prevent your code from crashing when errors occur, you can use the try statement in Python. This statement enables you to monitor your code for exceptions and take appropriate actions if they arise. This helps provide a smoother and more user-friendly experience.

Example -

Output:

Enter first number 32
1Enter second number 16
32.0 divided by 16.0 is 2.0
Enter first number 23
Enter second number 0
You can't divide by zero
Enter first number 12
Enter second number "five"
Please enter valid numbers

In the above code, we first capture user input as strings and then attempt to convert them to floats within the try block. We also check explicitly for division by zero before performing the division operation. Additionally, we added a catch-all except block to handle any unexpected errors that might occur during the executionof the code.

Handling Multiple Python Exceptions

Handling individual exceptions with separate except clauses is suitable when you need to execute different actions for each specific exception. However, if you notice that you're taking the same actions for multiple exceptions, you can create cleaner and more readable code by combining multiple exceptions into a single except clause. To achieve this, you can specify the exceptions as a tuple within the except statement.

Now, we will rewrite the above code to handle the exception in the single line. Let's understand the following example.

Example -

Output:

Enter first number 32
1Enter second number 16
32.0 divided by 16.0 is 2.0
Enter first number 23
Enter second number 0
You can't divide by zero
Enter first number 12
Enter second number "five"
Please enter valid numbers

In this scenario, you can use a single `except` clause to handle both `ValueError` and `ZeroDivisionError` exceptions. If needed, you can also include additional `except` clauses to handle other exceptions in a similar manner.

In the initial test, only the try block runs as there are no exceptions raised. In the second and third test cases, you intentionally trigger a ValueError and a ZeroDivisionError, respectively. You've effectively caught both of these exceptions using the same except clause. In both cases, the program follows the pattern of try, then except (handling ValueError or ZeroDivisionError). As we can see that the handler gracefully manages both exceptions.

Identifying the Captured Python Exception

In the object-oriented programming concept, classes act as templates defining the attributes and capabilities of the objects instantiate. When your code raises a Python exception, it effectively creates an object from the class that defines that exception. For instance, when a ValueError exception is raised, you're essentially creating an instance of the ValueError class.

You don't have to have a deep knowledge in object-oriented programming to handle exceptions, but it's helpful to know that different types of exceptions come from different classes. In simpler terms, exceptions are like different tools in a toolbox, and each tool has its own unique job to do when something goes wrong in your code.

Example -

Output:

Enter first number: 10
Enter second number: 2
10.0 divided by 2.0 is 5.0
Enter first number: 23
Enter second number: "two"
A ValueError has occurred.
Enter first number: 10
Enter second number: 0
A ZeroDivisionError has occurred.

Suppose you want to make your code better by adding the ability to multiply numbers. You also choose to raise a RuntimeError yourself if your user tries to do something unsupported or unexpected, such as pressing the Enter key.

Let's understand the following example -

Example -

Output:

Enter your first number: 10
Enter your second number: "h"
An error occurred: could not convert string to float: '"h"'
Enter a valid numbers.

In this updated version, we utilize the mul() and truediv() functions from the operator module to carry out multiplication and division operations. These functions are passed as arguments to the calculate() function, along with the two numerical inputs. Inside the calculate() function, the appropriate operator function (either `mul()` or `truediv()`) is called based on the chosen operation. This process successfully performs the calculation, but it is contingent upon providing two numerical inputs and specifying either '*' or '/' for the operation.

When a user enters an unsupported operator, your code intentionally triggers a RuntimeError. If this error isn't handled properly, it can lead to the code crashing.

In the `except` section, you specify a tuple of exceptions to catch, and you assign the caught exception to a variable called `error`. Initially, your code prints the name of the exception class, no matter which exception is raised. Subsequently, you use a match block to display a specific message based on the particular exception being handled. This way, you can provide relevant error messages to the user based on the type of error encountered.

Handling Multiple Possible Python Exceptions Using a Superclass

In Python, various exceptions are instances of distinct classes, all of which are part of the Python exception class hierarchy. Every Python exception is derived from a class called BaseException, and within this hierarchy, there exists a superclass known as the Exception class. This Exception class serves as the parent class for the exceptions we'll explore in this tutorial.

In the exceptions, inheritance primarily involves organizing exceptions into a hierarchy. For instance, you'll notice that ArithmeticError is a subclass of exception. In practice, the distinctions between these classes are minimal.

There are two subclasses of the OSError class: PermissionError and FileNotFoundError. This implies that both PermissionError and FileNotFoundError are subclasses of OSError, and consequently, they are also considered exception subclasses since OSError inherits from Exception.

Let's see the following example -

Example -

The code is written to print the contents of a file named datafile.txt, but it will only work if the file exists. If datafile.txt is not found, above code will raise a FileNotFoundError. While you have a single except clause that appears to catch OSError, it can also handle FileNotFoundError since the latter is a type of OSError.

To determine the specific subclass of OSError that you've encountered, you can utilize the `type(error).__name__` approach to print its class name. However, this might not be very meaningful to most users. Alternatively, you can discern the underlying error by inspecting the `.errno` attribute. This attribute contains a numerical code generated by the operating system, which offers insights into the nature of the issue that triggered the OSError. While the number it may not take much, the associated error message provides a more informative description of the problem.

Handle Multiple Python Exceptions Using contextlib.suppress()

In certain situations, your code may come across exceptions that need to be disregarded to ensure its functionality. These instances could involve scenarios like waiting for data from a network card that hasn't arrived yet or attempting to read a file that's currently locked by another user.

The conventional approach to handling exceptions in Python is to catch them without taking any specific action. This often results in code that looks like this.

Example -

To handle the FileNotFoundError that might arise if the file doesn't exist, you capture the exception as usual and utilize the "pass" keyword within the handler to essentially ignore it. Running your code under these circumstances results in no output, and importantly, your program doesn't terminate unexpectedly:

Using this approach in your code can potentially confuse the readers. You're essentially directing the program to capture an exception and subsequently warning it to indifference the exception entirely.

To create code that intentionally avoids handling exceptions, Python offers a context manager. You can utilize this manager by employing the suppress() function found within the contextlib module. In your case, you've chosen to implement your code using suppress().

Example -

In this code, you employ suppress() to establish a context manager designed to handle both FileNotFoundError and PermissionError exceptions. The with statement then applies this context manager to the code enclosed within its indentation. If you had raised a different type of exception, the code would still function correctly and not crash. However, it's essential to note that if you had placed any code outside of the "with" block, the exception suppression would not be in effect.

Here's another scenario: Imagine you have multiple files named "transactions.txt" created at different times throughout the day. These files contain data that you need to consolidate into a single file named "all_transactions.txt." After merging, your code archives the original file to "transactions.arch_ts," where "ts" represents a timestamp for uniqueness. However, there are occasions when your program searches for a file that simply doesn't exist.

Example -

This code continually checks for new transactions in the "transactions.txt" file, appends them to the "all_transactions.txt" file, and archives the original file with a timestamp. It uses suppress to handle FileNotFoundError gracefully if the temporary file doesn't exist.

Catch Multiple Python Exceptions Using Exception Groups

When you use a try...except block in your code, it has the capability to catch the initial exception that arises within the try block. However, if you attempt to raise multiple exceptions, the program will terminate after handling the first exception, and any subsequent exceptions will not be raised. This can be demonstrated using code similar to the following example.

Let's understand the following example -

Example -

In the given code, there is a list of exceptions containing instances of ZeroDivisionError, FileNotFoundError, and NameError. Three variables, num_zd_errors, num_fnf_errors, and num_name_errors, are initialized to zero.

Inside the try block, a loop iterates through the exceptions list and raises each exception. However, the code only catches and handles one exception at a time.

In the except block, there are separate clauses for ZeroDivisionError, FileNotFoundError, and NameError. Each clause increments the corresponding error count variable.

Finally, a finally block prints the counts of each type of exception raised.

Conclusion

This tutorial covers Python exception handling, emphasizing the importance of managing errors to prevent program crashes. It introduces the `try` and `except` statements for handling exceptions and demonstrates how to handle multiple exceptions efficiently. The tutorial also presents the use of contextlib.suppress() to ignore specific exceptions explicitly. Lastly, it highlights potential issues when raising multiple exceptions within a `try` block. Proper exception handling ensures code reliability and user-friendly error messages, enhancing overall program robustness.


Next TopicPython TOML




Latest Courses