20 Essential Python Exception Handling Techniques
This article presents twenty practical Python exception‑handling techniques—from basic try‑except structures and custom exceptions to advanced concepts like exception chaining, dynamic exception classes, and generator cleanup—providing developers with clear examples and explanations to write more robust, readable, and Pythonic code.
Exception handling is a crucial aspect of writing robust code. While many developers are familiar with basic try‑except blocks, there are deeper techniques that can make exception handling more efficient, readable, and Pythonic. This article presents 20 Python exception handling tricks that can significantly improve your code.
1. Simplest Exception Handling
We all know the simplest exception handling pattern:
try:
# Your code here
except IOError:
# Handle I/O errors
except Exception as e:
# Handle other exceptions
finally:
# Cleanup, runs no matter whatExceptions are organized in a hierarchy; if an IOError occurs, its except block runs, while other exceptions fall to the generic Exception handler. Understanding this hierarchy lets you catch errors more broadly or specifically as needed.
Using the finally clause ensures cleanup operations run regardless of whether an exception occurs, which is ideal for closing files or releasing resources.
2. Custom Exceptions
Creating custom exceptions can make code more readable and maintainable by clearly indicating specific error conditions.
class MyCustomError(Exception):
pass
try:
raise MyCustomError("A specific error occurred")
except MyCustomError as e:
print(e)3. Else in Try‑Except
If no exception is raised, the else clause of a try‑except block executes. This construct is not available in many other languages.
try:
# Attempt operation
except Exception:
# Handle error
else:
# Executes if no exceptions4. Using the as Keyword
The as keyword assigns the caught exception to a variable, allowing detailed inspection and easier debugging.
try:
# Some operation
except Exception as e:
print(f"Error: {e}")5. Capturing Multiple Exceptions
A tuple can be used to catch several exception types in a single except clause, simplifying error‑handling code.
try:
# Risky operation
except (TypeError, ValueError) as e:
# Handle both exceptions6. Raising a New Exception from Another
Python allows raising a new exception while preserving the original traceback using the from clause, which aids debugging complex scenarios.
try:
# Some operation
except Exception as original_error:
raise RuntimeError("Something bad happened") from original_errorThis technique can be powerful but should be used with care.
7. Ignoring Exceptions
The contextlib.suppress() function can gracefully ignore specific exceptions, making code clearer and more readable.
from contextlib import suppress
with suppress(FileNotFoundError):
# Operation that might not find a file8. Using Assertions
Assertions raise an exception when a condition is not met. Use them cautiously, as they can be disabled with optimization flags.
assert condition, "Condition was not met"AssertionError can be caught directly in an except block.
9. Formatting Exception Information
The traceback module can print detailed exception information, helping with debugging.
import traceback
try:
raise ValueError("An error occurred")
except:
traceback.print_exc() # Print exception information to stderr10. Emitting Non‑Fatal Warnings
The warnings module issues warnings instead of exceptions, useful for alerting users or developers without stopping execution.
import warnings
warnings.warn("This is a warning message", UserWarning)11. Suppressing Exceptions (repeat)
The suppress function from contextlib can ignore specific exceptions while ensuring resources are cleaned up.
from contextlib import suppress
with suppress(FileNotFoundError):
open('non_existent_file.txt', 'r')12. Creating an Exception‑Handling Wrapper
The functools module can be used to build a decorator that centralises exception handling across multiple functions.
from functools import wraps
def exception_handler(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Handled exception: {e}")
return None
return wrapper
@exception_handler
def risky_function():
raise ValueError("Something went wrong")
risky_function()13. Accessing Exception Attributes
sys.exc_info() provides detailed information about the current exception, useful for logging or further processing.
import sys
try:
raise TypeError("An error occurred")
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
print(exc_type, exc_value)14. Analysing the Current Exception Context
The inspect module can examine the current exception context, which is valuable in complex error‑handling scenarios.
import inspect
def current_exception():
for frame in inspect.trace():
if frame[3] == 'risky_function':
return frame[0].f_locals.get('e')
try:
risky_function()
except Exception as e:
print(current_exception())15. Creating Dynamic Exception Classes
The types module can dynamically create exception classes at runtime.
import types
DynamicException = types.new_class('DynamicException', (Exception,))
raise DynamicException("A dynamically created exception")16. Listing All Built‑in Exceptions
The builtins module can enumerate all built‑in exception types, helping you understand the hierarchy.
import builtins
for name in dir(builtins):
obj = getattr(builtins, name)
if isinstance(obj, type) and issubclass(obj, BaseException):
print(name)17. Customising Exception String Representation
Override __str__ and __repr__ in a custom exception to provide richer error messages.
class MyException(Exception):
def __str__(self):
return "This is a custom message for MyException"
def __repr__(self):
return "MyException()"
raise MyException18. Exceptions Not Caught by except Exception
Deriving from BaseException creates exceptions that bypass a generic except Exception block, useful for critical errors.
class MyCriticalError(BaseException):
pass
try:
raise MyCriticalError("A critical error")
except Exception as e:
print("This will not catch MyCriticalError")19. Gracefully Handling User and System Interrupts
Catching KeyboardInterrupt and SystemExit allows graceful shutdown of scripts.
import sys
try:
while True:
continue
except KeyboardInterrupt:
print("User interrupted the process")
sys.exit(0)20. Generator Resource Cleanup
GeneratorExit is raised when a generator is closed; catching it enables cleanup actions.
def my_generator():
try:
yield "Hello"
except GeneratorExit:
print("Generator closing")
raise
gen = my_generator()
next(gen)
gen.close()Conclusion
Python exceptions can greatly enhance code robustness and clarity. The 20 examples compiled in this article help you leverage Python's error‑handling capabilities and markedly improve your exception management.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.