本文目录导读:

我来详细讲解Python中捕获异常的多种方法和实践案例。
基础异常捕获结构
try-except 基础用法
# 基础捕获
try:
result = 10 / 0
except ZeroDivisionError:
print("除数不能为零!")
# 捕获多个异常
try:
num = int(input("请输入数字:"))
result = 10 / num
except ValueError:
print("请输入有效的数字!")
except ZeroDivisionError:
print("除数不能为零!")
# 捕获所有异常(不推荐,应尽量精确)
try:
# 一些操作
pass
except Exception as e:
print(f"发生错误:{e}")
实际应用案例
案例1:文件操作异常处理
def read_file(filename):
"""安全读取文件"""
try:
with open(filename, 'r', encoding='utf-8') as file:
content = file.read()
return content
except FileNotFoundError:
print(f"错误:文件 '{filename}' 不存在")
return None
except PermissionError:
print(f"错误:没有权限读取文件 '{filename}'")
return None
except Exception as e:
print(f"读取文件时发生未知错误:{e}")
return None
# 使用示例
content = read_file("data.txt")
if content:
print("文件内容:", content[:100])
案例2:网络请求异常处理
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError
def fetch_data(url, timeout=5):
"""安全获取网络数据"""
try:
response = requests.get(url, timeout=timeout)
response.raise_for_status() # 检查HTTP状态码
return response.json()
except Timeout:
print(f"错误:请求超时({timeout}秒)")
return None
except ConnectionError:
print(f"错误:无法连接到 {url}")
return None
except RequestException as e:
print(f"网络请求错误:{e}")
return None
except ValueError as e:
print(f"JSON解析错误:{e}")
return None
# 使用示例
data = fetch_data("https://api.example.com/data")
if data:
print("获取的数据:", data)
案例3:数据库操作异常处理
import sqlite3
from sqlite3 import Error as SQLError
class DatabaseManager:
def __init__(self, db_path):
self.db_path = db_path
self.connection = None
def connect(self):
"""安全连接数据库"""
try:
self.connection = sqlite3.connect(self.db_path)
print("数据库连接成功")
return True
except SQLError as e:
print(f"数据库连接失败:{e}")
return False
def execute_query(self, query, params=None):
"""安全执行SQL查询"""
try:
cursor = self.connection.cursor()
if params:
cursor.execute(query, params)
else:
cursor.execute(query)
self.connection.commit()
return cursor.fetchall()
except SQLError as e:
print(f"SQL执行错误:{e}")
self.connection.rollback()
return None
except AttributeError as e:
print(f"数据库未连接:{e}")
return None
def close(self):
"""安全关闭连接"""
try:
if self.connection:
self.connection.close()
print("数据库连接已关闭")
except SQLError as e:
print(f"关闭连接时出错:{e}")
# 使用示例
db = DatabaseManager("test.db")
if db.connect():
result = db.execute_query("SELECT * FROM users")
if result:
for row in result:
print(row)
db.close()
高级异常处理技巧
完整的异常处理结构
def advanced_error_handling():
"""演示完整的异常处理结构"""
try:
# 尝试执行的代码
print("正在执行操作...")
x = int(input("请输入数字:"))
result = 100 / x
print(f"结果:{result}")
except ValueError:
# 处理特定异常
print("请输入有效数字!")
except ZeroDivisionError:
# 处理除零异常
print("除数不能为零!")
except Exception as e:
# 处理其他所有异常
print(f"未知错误:{type(e).__name__}: {e}")
else:
# 没有异常时执行
print("操作成功完成!")
finally:
# 无论是否有异常都会执行
print("清理工作:关闭资源等")
# 运行示例
advanced_error_handling()
自定义异常类
class CustomError(Exception):
"""自定义异常基类"""
def __init__(self, message, code=None):
self.message = message
self.code = code
super().__init__(self.message)
def __str__(self):
if self.code:
return f"[{self.code}] {self.message}"
return self.message
class ValidationError(CustomError):
"""数据验证错误"""
pass
class BusinessError(CustomError):
"""业务逻辑错误"""
pass
# 使用自定义异常
def validate_age(age):
"""验证年龄"""
if not isinstance(age, int):
raise ValidationError("年龄必须是整数", code=1001)
if age < 0 or age > 150:
raise ValidationError(f"年龄 {age} 超出有效范围", code=1002)
return True
def process_user_data(age):
"""处理用户数据"""
try:
validate_age(age)
print(f"年龄 {age} 验证通过")
except ValidationError as e:
print(f"验证失败:{e}")
# 根据错误码处理
if e.code == 1001:
print("建议:请输入整数")
elif e.code == 1002:
print("建议:请输入0-150之间的年龄")
except Exception as e:
print(f"处理错误:{e}")
# 测试
process_user_data("25") # 类型错误
process_user_data(200) # 范围错误
process_user_data(25) # 正确
实际项目中的最佳实践
案例:完整的API调用封装
import time
import logging
from functools import wraps
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def retry_on_failure(max_retries=3, delay=1):
"""重试装饰器"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
last_exception = None
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except (ConnectionError, TimeoutError) as e:
last_exception = e
logger.warning(f"尝试 {attempt + 1}/{max_retries} 失败:{e}")
if attempt < max_retries - 1:
time.sleep(delay * (attempt + 1)) # 指数退避
logger.error(f"所有重试都失败")
raise last_exception
return wrapper
return decorator
class SafeAPIClient:
"""安全的API客户端"""
def __init__(self, base_url, api_key=None):
self.base_url = base_url
self.api_key = api_key
self.session = requests.Session()
if api_key:
self.session.headers.update({"Authorization": f"Bearer {api_key}"})
@retry_on_failure(max_retries=3)
def get_user_data(self, user_id):
"""获取用户数据(带重试机制)"""
try:
url = f"{self.base_url}/users/{user_id}"
response = self.session.get(url, timeout=10)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if response.status_code == 404:
logger.error(f"用户 {user_id} 不存在")
return None
elif response.status_code == 401:
logger.error("认证失败")
raise PermissionError("API密钥无效")
else:
raise
except requests.exceptions.ConnectionError:
logger.error("网络连接失败")
raise ConnectionError("无法连接到API服务器")
except requests.exceptions.Timeout:
logger.error("请求超时")
raise TimeoutError("API请求超时")
except Exception as e:
logger.exception(f"获取用户数据时发生未知错误")
raise
def close(self):
"""安全关闭会话"""
try:
self.session.close()
except Exception as e:
logger.error(f"关闭会话时出错:{e}")
# 使用示例
client = SafeAPIClient("https://api.example.com", api_key="your-api-key")
try:
user_data = client.get_user_data(12345)
if user_data:
print(f"用户数据:{user_data}")
except (ConnectionError, TimeoutError) as e:
print(f"网络错误:{e}")
except PermissionError as e:
print(f"权限错误:{e}")
finally:
client.close()
异常捕获的注意事项
常见陷阱和最佳实践
# ❌ 不好的做法:空except
try:
risky_operation()
except:
pass # 错误被忽略
# ✅ 好的做法:指定异常类型
try:
risky_operation()
except (ValueError, TypeError) as e:
logger.error(f"输入验证错误:{e}")
# ❌ 不好的做法:同时捕获异常又不处理
try:
result = calculate()
except Exception:
# 没有任何处理
pass
# ✅ 好的做法:始终进行适当的错误处理
try:
result = calculate()
except Exception as e:
logger.error(f"计算失败:{e}")
result = 0 # 设置默认值
raise # 或者重新抛出异常
# ❌ 不好的做法:过于宽泛的异常处理
try:
process_data()
except Exception:
print("出错了") # 丢失错误信息
# ✅ 好的做法:记录详细信息
try:
process_data()
except Exception as e:
logger.exception("处理数据时出错") # 记录完整堆栈跟踪
raise CustomError("数据处理失败", original_error=e)
- 精确捕获:尽量捕获特定异常类型
- 完整结构:充分利用 try-except-else-finally
- 适当记录:使用 logging 记录异常信息
- 重试机制:对临时性故障使用重试策略
- 资源清理:finally 或 with 语句确保资源释放
- 自定义异常:创建业务相关的异常类型
- 错误处理:不要忽略异常,要么处理要么重新抛出
这些实践能帮助你编写更健壮、更可维护的 Python 代码。