Catching Multiple Exception Types in Python
π£ Catching Multiple Exception Types in Pythonβ
In robust Python development, it is often necessary to catch and handle several different types of exceptions that might arise from a single block of code. Python provides flexible and concise syntax to manage multiple exceptions in a single try...except structure.
This article details the three primary methods for catching multiple exceptions, focusing on efficiency and best practice.
1. Method 1: The Single except Block (Using a Tuple)β
The most Pythonic and concise way to handle multiple specific exceptions with the same handling logic is to list them as a tuple following the except keyword.
Code Example: Tuple Catchingβ
def process_user_input(data):
try:
# Example 1: Failure during type conversion
value = int(data['count'])
# Example 2: Failure during calculation
result = 100 / value
# Catch both KeyError (if 'count' is missing) and ZeroDivisionError
except (KeyError, ZeroDivisionError) as e:
# This single block executes if EITHER exception occurs
print(f"--- Input Error Handled ---")
print(f"Caught {type(e).__name__}: {e}")
return None
except TypeError:
# Other exceptions can still be handled separately
print("Invalid data type provided.")
return None
# Test cases
process_user_input({}) # Triggers KeyError -> Handled
process_user_input({'count': '0'}) # Triggers ZeroDivisionError -> Handled
process_user_input({'count': 'text'}) # Triggers ValueError -> NOT Handled by the tuple
Key Takeaway: If the action you take (logging, cleanup, returning a default value) is identical for a group of exceptions, using a tuple is the cleanest solution.
2. Method 2: Multiple except Blocks (Different Logic)β
If you need distinct, specific handling logic for different exceptions, you must use separate except blocks. This allows you to tailor your response to the specific failure event.
Code Example: Separate Catchingβ
import os
import requests
def fetch_data_from_file_or_web(source):
if source.startswith('http'):
# Can raise requests.exceptions.Timeout
response = requests.get(source, timeout=2)
response.raise_for_status()
return response.json()
else:
# Can raise FileNotFoundError
with open(source, 'r') as f:
return f.read()
try:
fetch_data_from_file_or_web("https://api.timeout.com")
except requests.exceptions.Timeout:
# 1. Specific logic for network timeouts
print("FATAL: Network request timed out. Retrying later.")
# Log specific network metrics...
except FileNotFoundError:
# 2. Specific logic for missing files
print("WARNING: Local source file missing. Using cached data.")
# Report to a file inventory system...
except Exception as e:
# 3. Final safety net for anything else (like requests.exceptions.HTTPError)
print(f"ANOTHER ERROR: Unhandled exception occurred: {type(e).__name__}")
Key Takeaway: This is the standard pattern when the resolution, logging, or recovery strategy differs significantly between error types.
3. Method 3: Catching by Parent Class (Hierarchy)β
As detailed in the article on exception hierarchy, catching a base class will automatically catch all descendant exceptions. This is the most efficient way to handle a large group of related errors uniformly.
Recall that KeyError and IndexError both inherit from the base class LookupError.
Code Example: Parent Class Catchingβ
def get_element(collection, key):
# This might fail with a KeyError (if 'collection' is a dict)
# OR an IndexError (if 'collection' is a list)
return collection[key]
try:
get_element(['a', 'b'], 5) # Raises IndexError
get_element({'c': 3}, 'd') # Raises KeyError
# Catching LookupError handles both Index and Key Errors!
except LookupError as e:
print(f"Consolidated handler: Failed to access element. Type: {type(e).__name__}")
except ValueError:
# This is not a LookupError, so it is handled separately
print("Invalid value provided.")
Key Takeaway: Use parent classes like LookupError (for index/key issues), ArithmeticError (for division/overflow issues), or a custom application base class (AppBaseError) to simplify your except blocks.
Summary: Choosing the Right Methodβ
| Goal | Method | Syntax Example | Best For |
|---|---|---|---|
| Same Logic | Tuple Catching | except (KeyError, IndexError): | Grouping unrelated errors that require the exact same recovery action. |
| Different Logic | Separate Blocks | except KeyError: ... except IndexError: ... | Situations where you need to tailor the response (e.g., logging level, user message) for each specific failure. |
| Related Errors | Parent Class | except LookupError: ... | Handling a known family of errors (e.g., all file I/O errors via except OSError). |
