Skip to main content

Catching Multiple Exception Types in Python

Β· 6 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

🎣 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​

GoalMethodSyntax ExampleBest For
Same LogicTuple Catchingexcept (KeyError, IndexError):Grouping unrelated errors that require the exact same recovery action.
Different LogicSeparate Blocksexcept KeyError: ... except IndexError: ...Situations where you need to tailor the response (e.g., logging level, user message) for each specific failure.
Related ErrorsParent Classexcept LookupError: ...Handling a known family of errors (e.g., all file I/O errors via except OSError).

Sources and Further Reading​

  1. Python Documentation - Handling Multiple Exceptions
  2. Python Documentation - Built-in Exceptions (To identify parent classes)
  3. Real Python - Python Exception Handling (Focus on structure)
  4. Real Python - When to use multiple except blocks