Python 异常处理完全指南:try/except 写得好才能少踩坑
Introduction
代码里遇到错误怎么办?两种思路:
- <strong>EAFP</strong>(Easier to Ask Forgiveness than Permission):先尝试,出问题再处理——try/except
- <strong>LBYL</strong>(Look Before You Leap):先检查再行动——if/else
Python 偏好 EAFP 风格,但很多人写的异常处理其实是"捕获一切然后忽略",这不是异常处理,是把问题藏起来。
---
基础语法
1. 基本的 try/except
try:
result = 10 / int(user_input)
except ZeroDivisionError:
result = 0
except ValueError:
result = None
2. 捕获异常对象(获取错误详情)
try:
open("/etc/passwd")
except PermissionError as e:
print(f"权限不足: {e}")
print(f"文件名: {e.filename}")
except OSError as e:
print(f"系统错误: {e}")
3. else:没有异常时执行
try:
result = int(user_input)
except ValueError:
print("不是有效整数")
else:
# 只有 try 块完全正常执行时才会运行
print(f"转换成功: {result}")
4. finally:无论如何都执行
conn = None
try:
conn = open_database()
result = conn.query(sql)
finally:
# 不管成功还是异常,数据库连接必须关闭
if conn:
conn.close()
5. 自定义异常
class ValidationError(Exception):
"""数据校验失败异常"""
def __init__(self, field, message):
self.field = field
self.message = message
super().__init__(f"{field}: {message}")
# 使用
raise ValidationError("email", "格式不正确")
---
常见反模式
❌ 反模式1:捕获所有异常然后 pass
# 错误!
try:
do_something()
except:
pass
这会吞掉所有异常(包括 KeyboardInterrupt、SystemExit),让程序悄悄"死掉"。
✅ 正确做法:
try:
do_something()
except SpecificException as e:
logger.error(f"处理失败: {e}")
# 业务相关的 fallback 逻辑
❌ 反模式2:裸 except 太宽泛
# 错误!
except Exception:
print("出错了")
✅ 正确做法:捕获具体异常类型。
❌ 反模式3:异常里再抛异常没链
# 错误!原始异常信息丢失
try:
int("abc")
except ValueError:
raise RuntimeError("转换失败")
✅ 正确做法:用 raise ... from e 保留异常链:
try:
int("abc")
except ValueError as e:
raise RuntimeError("转换失败") from e
---
常见问题
Q1: 什么时候用异常,什么时候用 if/else?
- <strong>用 if/else</strong>:输入验证、简单的非黑即白判断
- <strong>用异常</strong>:真正异常情况、调用链深层需要通知调用者
Q2: 异常会影响性能吗?
正常情况下 try 不抛异常几乎没有开销。只有在频繁 try/except 在热路径(每秒调用上万次)才需要考虑优化。Q3: <code>with</code> 语句可以替代 finally 吗?
对于实现了__enter__/__exit__ 的对象(如文件、数据库连接),with 比 try/finally 更简洁:
# 简洁写法
with open("file.txt") as f:
data = f.read()
# 自动关闭,无需 finally
---
延伸阅读
- [[Python 日志模块 logging]] — 异常信息怎么记日志
- [[Python 单元测试中的异常测试]] — 用 pytest.raises 验证异常行为
- [[Python 上下文管理器]] — with 语句背后的原理
---
有问题欢迎在评论区交流!