Table of Contents
ToggleErrors are part of coding. Having a good understanding of error handling makes you a better developer. In this blog we will learn Python error handling best practices.
Why Error Handling is Important?
Error handling helps the application to gracefully tackle the error and prevents the application from crashing. It provides information about the error.
Overview of Python Error Handling
We can Handle errors in Python using exceptions. Exceptions are objects raised when errors occur during program execution. By handling the exceptions we can make our code failure proof.
What is an Exception in Python?
An exception is an object which is seen as an error that has occurred during code execution. When we get an exception the normal flow of the program is disturbed and control is transferred to an exception handler.
There are common Python exceptions
- SyntaxError : Occurs when we have syntax error in our code.
- ValueError: ValueError is raised when a function receives a valid parameter but the value of the parameter is invalid
- TypeError : Occurs when a function or operation is applied to an object of the wrong type. For example, if we try to add a number to a string, we get a type error.
- KeyError: Raised when key not found.
Python: Error Handling Best Practices
Catch only the exceptions you expect
Python Code
def divide_numbers(a, b): try: result = a / b return result except ZeroDivisionError: print("Error: Cannot divide by zero.") except TypeError: print("Error: Both arguments must be numbers.")
Using the Logging Module for Error Logging
Python code:
import logging logging.basicConfig(level=logging.ERROR) logging.error("An error occurred", exc_info=True)
Provide Meaningful Error Messages
Always provide meaningful error messages which help the developer in debugging the error. If we have a big code base and we use meaningful error messages it saves time and effort in understanding the issue.
Avoid Silencing Errors: Don't Ignore Them
Ignoring exceptions may cause bugs in the program and may lead to unintended flow of application. So it’s always important to handle the exceptions.
Using Warnings for Non-Critical Issues
Utilize the warnings module for issues that are not critical enough to raise exceptions.
Graceful Shutdowns and Cleanup on Errors
Implement cleanup actions within finally blocks or context managers to ensure resources are released properly.
Create Custom Exceptions for custom requirements
When developing an application we came across many different scenarios where we want to raise an error but we don’t have the correct exception. For cases like that we create custom exceptions.
Avoid Catching All Exceptions with a just except
Catching all exceptions can lead to unintended consequences just using ‘except’ Python.
def process_data(data): try: # Simulating some processing result = 10 / data # This can raise a ZeroDivisionError print(f"Result: {result}") except: # This will catch all exceptions, including SystemExit, KeyboardInterrupt, etc. print("An error occurred.") # Test with various inputs process_data(2) # Should work fine process_data(0) # Should raise ZeroDivisionError, but caught by the bare except process_data("a") # Should raise TypeError, but also caught by the bare except
Output
Result: 5.0 An error occurred. An error occurred.
Custom Exceptions in Python
class InsufficientFundsException(Exception): """Exception raised for errors in the account balance.""" def __init__(self, balance, amount): self.balance = balance self.amount = amount self.message = f"Insufficient funds: Available balance is {balance}, but attempted to withdraw {amount}." super().__init__(self.message) # Example function using the custom exception def withdraw(balance, amount): if amount > balance: raise InsufficientFundsException(balance, amount) return balance - amount # Usage try: new_balance = withdraw(100, 150) except InsufficientFundsException as e: print(e)Output
Insufficient funds: Available balance is 100, but attempted to withdraw 150.
Python error handling patterns
Using try and except Block
The primary error handling mechanism in Python is the try and except block.
Python template code : The code shows a framework of try and except.
try: # Code that may raise an exception except SomeException as e: # Handle the exception
Python code showing use of try and except to catch a ZeroDivisionError
try: # Code that may raise an exception result = 10 / 0 # This will raise a ZeroDivisionError except ZeroDivisionError as e: # Handle the exception print(f"Error: {e}. You cannot divide by zero!")
output
Error: division by zero. You cannot divide by zero!
Using else and finally for Complete Control
WE can also use else and finally to enhance control over error handling:
Python template code :
try: # Code that may raise an exception except SomeException: # Handle the exception else: # Code to execute if no exception occurs finally: # Code that will run regardless of exception occurrence
We will write a code for raising a zero division error with try except and finally Block.
def divide_numbers(num1, num2): try: result = num1 / num2 except ZeroDivisionError: print("Error: Cannot divide by zero.") else: print(f"The result is: {result}") finally: print("Execution completed.") # Example usage divide_numbers(10, 2) # This will succeed divide_numbers(10, 0) # This will raise an exception
Output
The result is: 5.0 Execution completed. Error: Cannot divide by zero. Execution completed.
Python API error handling best practices
Apply HTTP Status Codes whenever returning error or result
Return appropriate HTTP status codes to show the success or failure of requests so that the developer can direct the flow of the application.
- 200 OK: Successful requests.
- 400 Bad Request: Error on the Client-side (e.g., invalid input).
- 401 Unauthorized: Authentication failures.
- 403 Forbidden: Access denied.
- 404 Not Found: Resource not found / Url not found / page not found. .
- 500 Internal Server Error: Server-side errors.
Use Middleware for Global Error Handling
Python code
from flask import Flask, jsonify app = Flask(__name__) @app.errorhandler(Exception) def handle_exception(e): response = { "error": str(e), "status": 500 } return jsonify(response), 500The above code sets up a global error handler in Flask application. When a error occurs we get a JSON response with 500 as status code
Error Handling in Asynchronous Functions with async/await
Python code
import asyncio import aiohttp class FetchDataError(Exception): pass async def fetch_data(url): async with aiohttp.ClientSession() as session: try: async with session.get(url, timeout=5) as response: response.raise_for_status() # Raises an error for 4xx/5xx responses return await response.json() except asyncio.TimeoutError: raise FetchDataError("Request timed out") except aiohttp.ClientConnectionError: raise FetchDataError("Connection error occurred") except aiohttp.HttpProcessingError as e: raise FetchDataError(f"HTTP error: {e}") except Exception as e: raise FetchDataError(f"An unexpected error occurred: {e}") async def my_async_function(): url = "https://jsonplaceholder.typicode.com/posts/1" try: data = await fetch_data(url) print("Data fetched successfully:", data) except FetchDataError as e: print(f"Error in async operation: {e}") # Running the asynchronous function await my_async_function() #code is runned on google colab ipynb fileOutput:
Data fetched successfully: {'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto'}You can also use the requests library in python to raise exception like connection error or timeout error.
Test Error Scenarios
A good developer always writes unit tests and integration test to ensure that API handles errors as required.
Conclusion
Summary of python error handling best practices
- Catch specific exceptions and don’t generalize using ‘except’
- Use the logging module in Python for debugging.
- Provide logical error messages which would the user and developer know what is the issue
- Avoid silencing errors because they alter the flow of the program..
- Graceful Shutdowns and Cleanup on Errors
- Using Warnings for Non-Critical Issues
- Create custom exceptions when needed.
- Properly handle errors in asynchronous code.
- Always test your error handling code carefully.
References:
Errors and Exceptions
Pingback: Python got multiple values for argument
Pingback: How to Import Python Files from the Same Directory -