except*
?In Python 3.11+, ExceptionGroup
and except*
were introduced to simplify handling multiple exceptions raised concurrently (e.g., in parallel tasks or asynchronous code).
except*
: Catches specific exception types within the group, allowing you to handle each type separately.This is especially useful in modern Python apps using asyncio
or multithreading, where multiple errors can occur simultaneously.
ExceptionGroup
and except*
?Before Python 3.11, handling multiple exceptions required complex workarounds. Now:
try-except
blocks for concurrent tasks.try:
# Raise a group of exceptions
raise ExceptionGroup(
"error messages", # Description of the group
[ValueError("Invalid value"), TypeError("Wrong type")] # List of exceptions
)
except* ValueError as eg: # Catch all ValueErrors in the group
print(f"Handled ValueError: {eg.exceptions}")
except* TypeError as eg: # Catch all TypeErrors in the group
print(f"Handled TypeError: {eg.exceptions}")
Handled ValueError: (ValueError('Invalid value'),)
Handled TypeError: (TypeError('Wrong type'),)
Imagine fetching data from multiple URLs concurrently. Some requests might fail with different errors:
import asyncio
async def fetch_data(url):
# Simulate errors
if "example.com" in url:
raise ValueError("Invalid URL")
else:
raise TypeError("Data format mismatch")
async def main():
try:
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(fetch_data("https://example.com"))
task2 = tg.create_task(fetch_data("https://api.com"))
except* ValueError as eg:
print(f"URL errors: {eg.exceptions}")
except* TypeError as eg:
print(f"Data errors: {eg.exceptions}")
asyncio.run(main())
Process a form where multiple fields might have invalid data:
def validate_form(data):
errors = []
if not data["name"].isalpha():
errors.append(ValueError("Name must be alphabetic"))
if not isinstance(data["age"], int):
errors.append(TypeError("Age must be an integer"))
if errors:
raise ExceptionGroup("Form errors", errors)
try:
validate_form({"name": "Alice123", "age": "30"})
except* ValueError as eg:
print(f"Validation errors: {eg.exceptions}")
except* TypeError as eg:
print(f"Type errors: {eg.exceptions}")
Handle a payment system where transactions can fail with NetworkError
or InvalidAmountError
:
class NetworkError(Exception): pass
class InvalidAmountError(Exception): pass
errors = [
NetworkError("Connection timeout"),
InvalidAmountError("Amount must be positive")
]
try:
raise ExceptionGroup("Payment failed", errors)
except* NetworkError:
print("Retry payment due to network issues")
except* InvalidAmountError:
print("Fix the payment amount")
Clean a dataset that might have both ValueError
(invalid numbers) and KeyError
(missing fields):
data = [
{"value": "5"},
{"value": "abc"},
{} # Missing "value"
]
errors = []
for entry in data:
try:
int(entry["value"])
except Exception as e:
errors.append(e)
if errors:
raise ExceptionGroup("Data errors", errors)
Use a “catch-all” except*
to handle unprocessed errors:
try:
raise ExceptionGroup(
"errors",
[ValueError("bad value"), OSError("file not found")]
)
except* ValueError:
print("Handled ValueError")
except* Exception as eg: # Catch all other exceptions
print(f"Other errors: {eg.exceptions}")
except*
lets you handle each exception type in the group separately.except*
clauses from top to bottom.asyncio
, multithreading).Note: Ensure you’re using Python 3.11+! Check your version with:
python --version
Now go handle those errors like a pro! 🚀