Python异常处理
Python 异常处理的核心是 try/except/else/finally 四段结构 + "异常也是对象"的体系。与 Java 不同,Python 异常不区分受检/非受检——任何异常都可以选择捕获或忽略,编译器不强制。这种灵活性的代价是"异常被静默吞掉"成为常见 bug 源头,因此捕获精度和日志记录是 Python 异常处理的实践重点。
异常体系
Python 所有异常继承自 BaseException,程序可处理的异常继承 Exception(BaseException 直接子类 SystemExit/KeyboardInterrupt 通常不捕获):
BaseException
├── SystemExit # 退出解释器
├── KeyboardInterrupt # Ctrl+C
└── Exception # 程序可处理的所有异常
├── ValueError # 值不合法(int("abc"))
├── TypeError # 类型不匹配(1 + "a")
├── KeyError # 字典键不存在
├── IndexError # 下标越界
├── FileNotFoundError # 文件不存在
└── ... # 其余内置异常try/except/else/finally
try 放可能出错的代码,except 捕获处理,else 在无异常时执行,finally 无论是否异常都执行:
try:
num = int("abc") # 抛 ValueError
except ValueError as e: # 精确捕获 + 拿到异常对象
print(f"转换失败: {e}")
except (TypeError, KeyError): # 多个异常同一处理
print("其他错误")
else:
print("没有异常时执行") # 可选
finally:
print("无论如何都执行") # 释放资源、关闭连接else 的用途
else 区分"try 正常完成的后续"与"异常处理的后续":正常路径代码放 else 里,避免它被 except 误捕获,也让代码意图更清晰。return 在 try 里也会先执行 finally 再返回。
异常链与手动抛出
raise 手动抛异常,raise ... from ... 保留原始异常链——排查根因时原始异常不可丢:
def load_config(path):
try:
with open(path) as f:
return f.read()
except FileNotFoundError as e:
raise RuntimeError(f"配置文件缺失: {path}") from e # 保留原始异常# 主动校验参数
def divide(a, b):
if b == 0:
raise ValueError("除数不能为 0")
return a / b自定义异常
自定义异常继承 Exception,命名以 Error 结尾,通常只需一个 init 传 message:
class BusinessError(Exception):
def __init__(self, code, message):
super().__init__(message)
self.code = code
self.message = message
raise BusinessError(1001, "库存不足")自定义异常的价值:让调用方按业务语义捕获(except BusinessError),而不是裸捕获 Exception 再猜错误类型——这是大型项目错误处理的基础规范。
上下文管理器与 with
with 语句通过 __enter__/__exit__ 协议自动管理资源,替代手动 try/finally——文件、锁、数据库连接的标准写法:
# 等价于 try: f = open(...) ... finally: f.close()
with open("a.txt") as f:
content = f.read() # 离开 with 自动 close
# 自定义上下文管理器
class ManagedResource:
def __enter__(self): # 进入时执行
print("获取资源")
return self
def __exit__(self, exc_type, exc_val, exc_tb): # 退出时执行(无论异常与否)
print("释放资源")
return False # False 表示不吞异常,True 则吞掉
with ManagedResource() as r:
pass什么时候用 with
所有"打开-使用-关闭"模式的资源(文件、socket、线程锁、数据库连接)一律用 with;contextlib.contextmanager 装饰器可把生成器函数快速变成上下文管理器,见 Python函数式编程 的装饰器章节。
实践规范
| 规则 | 说明 |
|---|---|
| 精确捕获 | except ValueError 而非裸 except:,避免掩盖真实错误 |
| 保留异常链 | 二次抛出用 from e,不丢根因 |
| 记录日志 | 捕获后至少 logging.exception(...),禁止空 except |
| 不过度捕获 | 预料外错误让其抛出,靠日志发现 |
| 用 with 管理资源 | 替代手写 try/finally |
import logging
try:
process()
except ValueError:
logging.exception("处理失败") # 自动带上堆栈异常处理与 Python语法 的控制流、Python函数式编程 的装饰器(如重试装饰器基于异常捕获)配合使用。