Techno Blender
Digitally Yours.

Mastering Python Exception Handling: Expert Tips and Tricks

0 50


Image by Thomas Malyska from Pixabay

Discover the Hidden Secrets of Python Exception Handling

One important aspect of Python programming is exception handling, which refers to the way that errors and unexpected events are handled during the execution of a program. Exception handling is essential for writing robust and reliable code, as it enables programmers to handle errors and exceptions in a structured and controlled manner.

In this article, I will provide a comprehensive guide to Python exception handling, covering everything from basic try-except blocks to more advanced techniques. Whether you are new to Python programming or an experienced developer (You can start from section 3), this article will provide you with a complete overview of exception handling in Python, along with some useful tricks and tips that you may not have encountered before. So, whether you are just starting out with Python or looking to improve your exception handling skills, this article is the perfect resource to help you get started.

Image by Saul from Pixabay

1.1 The Simplest Exception Handling

Let’s start with the simplest exception handling in Python. Basically, we have a piece of code that may have any exceptions during the run time, we can put them in the “try” block. Then, in the “except” block, we can do something with it, such as displaying some message to indicate that there was an error.

try:
# Code that may raise an exception
x = 5 / 0
except:
# Code to handle the exception
print("An error occurred")

Also, please be noticed that the program did run successfully. Although there is an error, but we “caught” the error so that it is not considered “crush”.

1.2 Catch Specific Types of Exceptions

Sometimes, the piece of code may potentially result in different types of exceptions. Also, we may want to handle different types of exceptions in different ways. In this case, we can specify the type of error after the except keyword. Also, we can chain multiple except blocks to handle more than one type of error.

try:
x = 5 / 0
except ZeroDivisionError:
print("You can't divide a number by zero!")
except:
print("Unknown error occurred")

It is common to have the last except block without an explicit error type. So, if there is no except-block above caught the exception, it will fall in the last one.

try:
x = int("foo")
except ZeroDivisionError:
print("You can't divide a number by zero!")
except:
print("Unknown error occurred")

In this example, the error should actually be a TypeError because the string "foo" cannot be converted into a number. Therefore, the ZeroDivisionError did not catch the exception. So, it falls in the default except block eventually.

1.3 Access Details of the Exception

Regarding the above “Unknown” error, is there any way to obtain more information from the exception? In other words, although something unexpected happened, do we have such a method to have some clue what is the exception about?

The answer is yes. We can put an argument after the except keyword and access the details of the exception from this argument variable.

try:
x = int("foo")
except ZeroDivisionError:
print("You can't divide a number by zero!")
except Exception as e:
print("An Error occurred:", e)

In this example, we use Exception which is the parent class of all types of exceptions after the except keyword, and catch this exception as the variable e.

That is equivalent to saying, “please catch any type of exception in the variable e”. Then, we can print the variable to get the message. So, we know that the exception is actually we are trying to convert a literal string to an integer.

Image by LaterJay Photography from Pixabay

Now, let’s have a look at some practical usage patterns of exception handling in Python. In this section, the demo will be conducted in Python functions.

2.1 Without Exception Handling

What if we don’t handle the exception? Of course, the program will crash. Let’s have a look at how the “Traceback” tell us about the error.

def divide(x, y):
return x / y

def calculate(a, b):
result = divide(a, b)
print("Result:", result)

calculate(10, 0)

The program starts at the calculate(0, 0), then the calculate() function calls the divide() function. In the above example, the x / y in the divide() caused the ZeroDivisionError.

Looking at the traceback, the last block tells us where the exception comes from. Since there is no exception handling, it throws the exception back to its parent function calculate() body. Inside this function, the exception still has not been handled. Therefore, it throws again to its parent, where we called this calculate() function. The program crashed because the exception is not handled and reached the root level.

2.2 A Program with Exception Handling

Hold on, that means we don’t have to handle exceptions whenever it may occur. Instead, we can handle them at a certain and appropriate level.

For example, there is one line of code called one function, inside this function it calls many other functions that may cause different types of exceptions. In this case, we may only need to put this one line of code in the try-except block so that it will be handled.

def divide(x, y):
return x / y

def calculate(a, b):
try:
result = divide(a, b)
print("Result:", result)
except ZeroDivisionError:
print("You can't divide a number by zero!")

calculate(10, 0)

In the above example, we have an exception handling in the calculate() function. Although the exception happened in the divide() function, it will throw it to the parent level and be caught in the calculate() function.

2.3 The Finally Block

Well, I want to make this article a completed guide to Python Exception Handling. So, I guess let’s simply explore the finally block.

Long story short, the code in the finally block will be executed regardless if there are exceptions.

try:
x = 5 / 1
except ZeroDivisionError:
print("You can't divide a number by zero!")
finally:
print("Calculation finished")

One of the most common use cases of the finally block is to close resources such as database connections and opened files. This is a very good manner to avoid unexcepted behaviours or memory leaks.

2.4 Raise an Exception Deliberatively

Rather than catching an exception, we can also deliberately raise an exception. This could be very useful for debugging and control flow purposes that allow us to jump to a different part of the code or exit the program.

def calculate(a, b):
try:
raise Exception("I just want to raise an exception!")
except Exception as e:
print(e)

calculate(10, 0)

Image by Pexels from Pixabay

If you’re not new to Python, you may have skipped ahead to this section looking for some advanced techniques or knowledge gaps to fill. I hope this section can provide you with new insights and help you further refine your understanding of exception handling in Python.

3.1 Else Block

Do you know that the try ... except ... finally are not everything in Python exception handling? I guess you may not know that we can also use else in exception handling. The else block will only be executed if there is no exception.

try:
x = 5 / 1
except ZeroDivisionError:
print("You can't divide a number by zero!")
else:
print("The result is: ", x)
finally:
print("Calculation finished")

In fact, the else block is not a must-known thing. Theoretically, we can put the code after the line that may cause the exception. It will run anyway if there is no exception.

However, there are several weak reasons that we may want to use the else block. Firstly, it may improve readability because it is pretty natural to understand it as such: “if there is an exception, handle it like this, else please execute this code”. Secondly, the else block physically separated the code which may cause exceptions and the code won’t.

3.2 Warning Module

This might not be closely related to exception handling. However, some readers may be interested in this. If you have ever used Pandas library, sometimes it will give us warnings if we used some deprecated API or doing things with risks.

How this is done? The answer is to use the warning module.

import warnings

def calculate(x, y):
try:
result = x / y
except ZeroDivisionError:
print("You can't divide a number by zero!")
else:
if x == result:
warnings.warn("All numbers divide by 1 will remain the same.")
print("Result: ", result)

calculate(10, 1)

3.3 Assertion — Another Way of Raising an Exception

Another related technique in Python is the assertions. It is used to check whether a certain condition is true or false during the execution of a program. If the condition is true, the program continues executing normally. If the condition is false, an AssertionError is raised, interrupting the normal flow of the program.

def calculate(x, y):
assert y != 0, "You can't divide a number by zero!"
result = x / y
print("Result: ", result)

calculate(10, 0)

The assertion is commonly used for debugging and unit testing in Python. If the condition is satisfied, nothing will happen.

def calculate(x, y):
assert y != 0, "You can't divide a number by zero!"
result = x / y
print("Result: ", result)

calculate(10, 1)

3.4 Custom Exception Type

Sometimes, we may want to define and use custom exception types when we want to provide more specific and informative error messages to the user, or when we want to differentiate between different types of errors that can occur in our code.

We can define a custom exception as simply as follows.

class CustomException(Exception):
def __init__(self, message):
super().__init__(message)

raise CustomException("This is a custom exception")

Of course, we can do whatever we like because this is a customised class.

class CustomException(Exception):
def __init__(self, message):
super().__init__(message)

def __str__(self):
return f"A customised exception has occured: {self.args[0]}"

raise CustomException("This is a custom exception")

Using custom exceptions in Python allows us to exercise our imagination and provides the maximum level of flexibility in handling errors and exceptions in our code.

Image by Gerd Altmann from Pixabay

In the last section, I want to introduce the suppress module in the contextlib. It is built-in into Python, but fewer people know about it and it is rarely used. However, it can be very useful in some cases.

Suppose we have some lines of code that may cause exceptions. However, we may don’t care about these exceptions. Therefore, rather than raising these exceptions and handling them, the easiest way is to ignore them, or “suppress” them.

For example, the code below will output nothing.

from contextlib import suppress

with suppress(ZeroDivisionError):
x = 5 / 0
print(x)

The above code uses a with-statement together with the suppress function. It will ignore all the ZeroDivisionError happens in the code inside.

Why it is useful? Think about we have a series of user inputs. Some of the input values may not be valid. Suppose we don’t care about the invalid inputs at all. Instead, we just want to ignore them and process those that are valid.

Let’s simulate the scenario by having a list of items.

nums = [3, -1, -2, 1, 1, 0, 3, 1, -2, 1, 0, -1, -1, -1, 3, -2, -1, 3, '3', -1] 

result = 0
for num in nums:
with suppress(ZeroDivisionError, TypeError):
result += 1/num

As shown above, those zeros and strings are simply ignored. The code looks pretty neat and clean.

If you want to explore more for the suppress module more, I have a particular article that will do a deep dive.

Image by Mirka from Pixabay

In this article, we have explored the different aspects of Python exception handling. There were some useful tricks and tips for handling exceptions, such as using the warning module and suppressing specific exceptions with the suppress module.

By mastering exception handling in Python, you can write more robust and reliable code that can handle unexpected events and errors in a structured and controlled way. Whether you are a beginner or an experienced Python developer, understanding exception handling is essential for writing effective and efficient code. I hope that this article has provided you with a comprehensive guide to Python exception handling and some useful tips and tricks to help you improve your exception handling skills.

If you feel my articles are helpful, please consider joining Medium Membership to support me and thousands of other writers! (Click the link above)

Unless otherwise noted all images are by the author


Image by Thomas Malyska from Pixabay

Discover the Hidden Secrets of Python Exception Handling

One important aspect of Python programming is exception handling, which refers to the way that errors and unexpected events are handled during the execution of a program. Exception handling is essential for writing robust and reliable code, as it enables programmers to handle errors and exceptions in a structured and controlled manner.

In this article, I will provide a comprehensive guide to Python exception handling, covering everything from basic try-except blocks to more advanced techniques. Whether you are new to Python programming or an experienced developer (You can start from section 3), this article will provide you with a complete overview of exception handling in Python, along with some useful tricks and tips that you may not have encountered before. So, whether you are just starting out with Python or looking to improve your exception handling skills, this article is the perfect resource to help you get started.

Image by Saul from Pixabay

1.1 The Simplest Exception Handling

Let’s start with the simplest exception handling in Python. Basically, we have a piece of code that may have any exceptions during the run time, we can put them in the “try” block. Then, in the “except” block, we can do something with it, such as displaying some message to indicate that there was an error.

try:
# Code that may raise an exception
x = 5 / 0
except:
# Code to handle the exception
print("An error occurred")

Also, please be noticed that the program did run successfully. Although there is an error, but we “caught” the error so that it is not considered “crush”.

1.2 Catch Specific Types of Exceptions

Sometimes, the piece of code may potentially result in different types of exceptions. Also, we may want to handle different types of exceptions in different ways. In this case, we can specify the type of error after the except keyword. Also, we can chain multiple except blocks to handle more than one type of error.

try:
x = 5 / 0
except ZeroDivisionError:
print("You can't divide a number by zero!")
except:
print("Unknown error occurred")

It is common to have the last except block without an explicit error type. So, if there is no except-block above caught the exception, it will fall in the last one.

try:
x = int("foo")
except ZeroDivisionError:
print("You can't divide a number by zero!")
except:
print("Unknown error occurred")

In this example, the error should actually be a TypeError because the string "foo" cannot be converted into a number. Therefore, the ZeroDivisionError did not catch the exception. So, it falls in the default except block eventually.

1.3 Access Details of the Exception

Regarding the above “Unknown” error, is there any way to obtain more information from the exception? In other words, although something unexpected happened, do we have such a method to have some clue what is the exception about?

The answer is yes. We can put an argument after the except keyword and access the details of the exception from this argument variable.

try:
x = int("foo")
except ZeroDivisionError:
print("You can't divide a number by zero!")
except Exception as e:
print("An Error occurred:", e)

In this example, we use Exception which is the parent class of all types of exceptions after the except keyword, and catch this exception as the variable e.

That is equivalent to saying, “please catch any type of exception in the variable e”. Then, we can print the variable to get the message. So, we know that the exception is actually we are trying to convert a literal string to an integer.

Image by LaterJay Photography from Pixabay

Now, let’s have a look at some practical usage patterns of exception handling in Python. In this section, the demo will be conducted in Python functions.

2.1 Without Exception Handling

What if we don’t handle the exception? Of course, the program will crash. Let’s have a look at how the “Traceback” tell us about the error.

def divide(x, y):
return x / y

def calculate(a, b):
result = divide(a, b)
print("Result:", result)

calculate(10, 0)

The program starts at the calculate(0, 0), then the calculate() function calls the divide() function. In the above example, the x / y in the divide() caused the ZeroDivisionError.

Looking at the traceback, the last block tells us where the exception comes from. Since there is no exception handling, it throws the exception back to its parent function calculate() body. Inside this function, the exception still has not been handled. Therefore, it throws again to its parent, where we called this calculate() function. The program crashed because the exception is not handled and reached the root level.

2.2 A Program with Exception Handling

Hold on, that means we don’t have to handle exceptions whenever it may occur. Instead, we can handle them at a certain and appropriate level.

For example, there is one line of code called one function, inside this function it calls many other functions that may cause different types of exceptions. In this case, we may only need to put this one line of code in the try-except block so that it will be handled.

def divide(x, y):
return x / y

def calculate(a, b):
try:
result = divide(a, b)
print("Result:", result)
except ZeroDivisionError:
print("You can't divide a number by zero!")

calculate(10, 0)

In the above example, we have an exception handling in the calculate() function. Although the exception happened in the divide() function, it will throw it to the parent level and be caught in the calculate() function.

2.3 The Finally Block

Well, I want to make this article a completed guide to Python Exception Handling. So, I guess let’s simply explore the finally block.

Long story short, the code in the finally block will be executed regardless if there are exceptions.

try:
x = 5 / 1
except ZeroDivisionError:
print("You can't divide a number by zero!")
finally:
print("Calculation finished")

One of the most common use cases of the finally block is to close resources such as database connections and opened files. This is a very good manner to avoid unexcepted behaviours or memory leaks.

2.4 Raise an Exception Deliberatively

Rather than catching an exception, we can also deliberately raise an exception. This could be very useful for debugging and control flow purposes that allow us to jump to a different part of the code or exit the program.

def calculate(a, b):
try:
raise Exception("I just want to raise an exception!")
except Exception as e:
print(e)

calculate(10, 0)

Image by Pexels from Pixabay

If you’re not new to Python, you may have skipped ahead to this section looking for some advanced techniques or knowledge gaps to fill. I hope this section can provide you with new insights and help you further refine your understanding of exception handling in Python.

3.1 Else Block

Do you know that the try ... except ... finally are not everything in Python exception handling? I guess you may not know that we can also use else in exception handling. The else block will only be executed if there is no exception.

try:
x = 5 / 1
except ZeroDivisionError:
print("You can't divide a number by zero!")
else:
print("The result is: ", x)
finally:
print("Calculation finished")

In fact, the else block is not a must-known thing. Theoretically, we can put the code after the line that may cause the exception. It will run anyway if there is no exception.

However, there are several weak reasons that we may want to use the else block. Firstly, it may improve readability because it is pretty natural to understand it as such: “if there is an exception, handle it like this, else please execute this code”. Secondly, the else block physically separated the code which may cause exceptions and the code won’t.

3.2 Warning Module

This might not be closely related to exception handling. However, some readers may be interested in this. If you have ever used Pandas library, sometimes it will give us warnings if we used some deprecated API or doing things with risks.

How this is done? The answer is to use the warning module.

import warnings

def calculate(x, y):
try:
result = x / y
except ZeroDivisionError:
print("You can't divide a number by zero!")
else:
if x == result:
warnings.warn("All numbers divide by 1 will remain the same.")
print("Result: ", result)

calculate(10, 1)

3.3 Assertion — Another Way of Raising an Exception

Another related technique in Python is the assertions. It is used to check whether a certain condition is true or false during the execution of a program. If the condition is true, the program continues executing normally. If the condition is false, an AssertionError is raised, interrupting the normal flow of the program.

def calculate(x, y):
assert y != 0, "You can't divide a number by zero!"
result = x / y
print("Result: ", result)

calculate(10, 0)

The assertion is commonly used for debugging and unit testing in Python. If the condition is satisfied, nothing will happen.

def calculate(x, y):
assert y != 0, "You can't divide a number by zero!"
result = x / y
print("Result: ", result)

calculate(10, 1)

3.4 Custom Exception Type

Sometimes, we may want to define and use custom exception types when we want to provide more specific and informative error messages to the user, or when we want to differentiate between different types of errors that can occur in our code.

We can define a custom exception as simply as follows.

class CustomException(Exception):
def __init__(self, message):
super().__init__(message)

raise CustomException("This is a custom exception")

Of course, we can do whatever we like because this is a customised class.

class CustomException(Exception):
def __init__(self, message):
super().__init__(message)

def __str__(self):
return f"A customised exception has occured: {self.args[0]}"

raise CustomException("This is a custom exception")

Using custom exceptions in Python allows us to exercise our imagination and provides the maximum level of flexibility in handling errors and exceptions in our code.

Image by Gerd Altmann from Pixabay

In the last section, I want to introduce the suppress module in the contextlib. It is built-in into Python, but fewer people know about it and it is rarely used. However, it can be very useful in some cases.

Suppose we have some lines of code that may cause exceptions. However, we may don’t care about these exceptions. Therefore, rather than raising these exceptions and handling them, the easiest way is to ignore them, or “suppress” them.

For example, the code below will output nothing.

from contextlib import suppress

with suppress(ZeroDivisionError):
x = 5 / 0
print(x)

The above code uses a with-statement together with the suppress function. It will ignore all the ZeroDivisionError happens in the code inside.

Why it is useful? Think about we have a series of user inputs. Some of the input values may not be valid. Suppose we don’t care about the invalid inputs at all. Instead, we just want to ignore them and process those that are valid.

Let’s simulate the scenario by having a list of items.

nums = [3, -1, -2, 1, 1, 0, 3, 1, -2, 1, 0, -1, -1, -1, 3, -2, -1, 3, '3', -1] 

result = 0
for num in nums:
with suppress(ZeroDivisionError, TypeError):
result += 1/num

As shown above, those zeros and strings are simply ignored. The code looks pretty neat and clean.

If you want to explore more for the suppress module more, I have a particular article that will do a deep dive.

Image by Mirka from Pixabay

In this article, we have explored the different aspects of Python exception handling. There were some useful tricks and tips for handling exceptions, such as using the warning module and suppressing specific exceptions with the suppress module.

By mastering exception handling in Python, you can write more robust and reliable code that can handle unexpected events and errors in a structured and controlled way. Whether you are a beginner or an experienced Python developer, understanding exception handling is essential for writing effective and efficient code. I hope that this article has provided you with a comprehensive guide to Python exception handling and some useful tips and tricks to help you improve your exception handling skills.

If you feel my articles are helpful, please consider joining Medium Membership to support me and thousands of other writers! (Click the link above)

Unless otherwise noted all images are by the author

FOLLOW US ON GOOGLE NEWS

Read original article here

Denial of responsibility! Techno Blender is an automatic aggregator of the all world’s media. In each content, the hyperlink to the primary source is specified. All trademarks belong to their rightful owners, all materials to their authors. If you are the owner of the content and do not want us to publish your materials, please contact us by email – [email protected]. The content will be deleted within 24 hours.
Leave a comment