本文专为初/中级Python开发者设计,通过6个实战案例和3个工程级解决方案,系统掌握异常处理的核心技能。所有代码均基于Python 3.8+验证,可直接集成到实际项目中。
def safe_division(a: float, b: float) -> float:
"""带完整异常处理的除法函数"""
result = None
try:
print("尝试除法运算...")
result = a / b # 可能触发ZeroDivisionError
except ZeroDivisionError:
print("⚠️ 除数不能为零!")
except TypeError as e:
print(f"⚠️ 类型错误:{e}")
else:
print(f"✅ 计算结果:{result}")
finally:
print(" 运算流程结束")
return result if result is not None else float('nan')
# 测试用例
print(safe_division(10, 2)) # 正常情况
print(safe_division(10, 0)) # 除零错误
print(safe_division("10", 2)) # 类型错误
执行流程解析:
try
:监控可能出错的代码except
:按从具体到一般的顺序捕获异常(ZeroDivisionError
比Exception
更具体)else
:仅当无异常时执行,放置业务逻辑代码finally
:必定执行的资源清理操作(如关闭文件、释放锁)异常类型 | 典型触发场景 | 解决方案 |
---|---|---|
ValueError |
int("abc") |
输入验证 + 类型转换 |
TypeError |
1 + "1" |
类型检查 + 转换 |
FileNotFoundError |
open("missing.txt") |
路径检查 + 异常处理 |
KeyError |
dict["missing_key"] |
使用.get() 或预先检查 |
IndexError |
list[100] |
索引范围检查 |
def process_user_input(input_str: str):
"""处理用户输入的综合异常案例"""
try:
num = float(input_str) # 可能触发ValueError
if num < 0:
raise ValueError("数值不能为负数") # 主动抛出异常
return num ** 0.5
except (ValueError, TypeError) as e:
print(f"输入错误: {e}")
return None
# 测试
process_user_input("abc") # 无效字符串
process_user_input("-100") # 主动抛出的异常
关键技巧:
except (TypeError, ValueError)
as e
获取异常对象,提取错误详情class APIException(Exception):
"""标准API异常基类"""
def __init__(self, message: str, code: int = 500):
super().__init__(message)
self.code = code # HTTP状态码
self.timestamp = datetime.now()
class RateLimitError(APIException):
"""API速率限制异常"""
def __init__(self, retry_after: int):
super().__init__("请求过于频繁", 429)
self.retry_after = retry_after # 重试等待时间
# 使用场景
def call_api():
if rate_limit_exceeded:
raise RateLimitError(retry_after=60)
try:
call_api()
except RateLimitError as e:
print(f"请求被限流!{e.retry_after}秒后重试")
time.sleep(e.retry_after)
设计原则:
Exception
基类PaymentFailedError
)try:
config = json.load(open("config.json"))
except FileNotFoundError as e:
raise ConfigError("配置文件缺失") from e
输出:
ConfigError: 配置文件缺失
The above exception was the direct cause of the following exception:
FileNotFoundError: [Errno 2] No such file...
def read_file_with_retry(
path: str,
max_attempts: int = 3,
encodings: tuple = ("utf-8", "gbk", "latin1")
) -> str:
"""带异常处理和编码探测的文件读取"""
for attempt in range(max_attempts):
try:
for encoding in encodings:
try:
with open(path, "r", encoding=encoding) as f:
return f.read()
except UnicodeDecodeError:
continue # 尝试下一种编码
raise UnicodeError("无法解析文件编码")
except (FileNotFoundError, PermissionError) as e:
if attempt == max_attempts - 1:
raise # 重试后仍失败
time.sleep(2 ** attempt) # 指数退避策略
return "" # 保证函数有返回值
import tempfile
import os
def atomic_write(file_path: str, content: str):
"""原子写入文件(写入完成才替换原文件)"""
temp_fd, temp_path = tempfile.mkstemp(dir=os.path.dirname(file_path))
try:
with os.fdopen(temp_fd, "w") as f:
f.write(content)
os.replace(temp_path, file_path) # 原子替换
except Exception:
os.remove(temp_path) # 清理临时文件
raise
关键防御点:
场景 | 最佳实践 | 反模式 |
---|---|---|
捕获范围 | 精确捕获(如except FileNotFoundError ) |
裸except: 或except Exception |
资源清理 | 使用with 语句或finally 块 |
依赖手动关闭资源 |
日志记录 | 记录完整堆栈:logging.exception(e) |
仅打印错误消息print(e) |
异常忽略 | 显式捕获后pass并写注释 | 空except块 |
自定义异常 | 继承自业务相关基类 | 直接继承BaseException |
class DatabaseConnection:
"""带自动重连的数据库连接管理器"""
def __enter__(self):
self.conn = connect_db()
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is ConnectionError:
self.reconnect() # 自动重连
elif exc_type:
log_error(f"操作失败: {exc_val}")
self.conn.close() # 确保连接关闭
立即动手:
“优秀的异常处理不是避免错误,而是将随机失败转化为可控状态”—— 通过合理的错误处理策略,可使系统可靠性提升10倍以上
更多技术干货欢迎关注微信公众号“风雨同舟的AI笔记”~
【转载须知】:转载请注明原文出处及作者信息