当前位置: 首页 > news >正文

08-Python异常处理-你写的try-except可能比不写更危险

文章目录

  • Python 异常处理:你写的 try-except 可能比不写更危险
    • 导入语
    • 1 ~> Python 的异常体系——一张图看清楚
    • 2 ~> 最常见的四种错误写法
      • 2.1 错误一:裸捕获 `except:`
      • 2.2 错误二:捕获范围过大 `except Exception`
      • 2.3 错误三:吞掉异常 `except: pass`
      • 2.4 错误四:在 finally 里写 return
    • 3 ~> try/except/else/finally 完整的四块
    • 4 ~> 异常链——一个真实场景
    • 5 ~> 自定义异常
    • 思考 && 总结
    • 结尾

Python 异常处理:你写的 try-except 可能比不写更危险

📖文章简介:这篇文章至少能帮你改掉两个坏习惯:except:裸捕获和except Exception: pass吞异常。初学 try-except 的时候,本能反应是"用 try 包住所有可能报错的代码,except 后面写 pass 就行"。但这两招在生产环境中会让你的 Bug 隐形。本文从 Python 异常体系结构讲起,拆解 try/except/else/finally 四块完整的语法和各自执行的时机,深入"捕获范围过大"“吃掉异常”“异常链”"自定义异常"四个核心场景,文末附真实案例——一条因为裸 except 吞掉了 PermissionError 导致数据不一致的生产事故。


🎬 个人主页:源码骑士

专栏传送门:《Android开发基础》《python基础课程》

⭐️热衷从源码视角拆解技术底层原理,将复杂架构讲得通俗易懂


🎬 源码骑士的简介:
5年Android Framework系统开发经验,曾主导多项系统级性能优化专项
技术栈覆盖Android系统全链路(Binder/Handler/AMS/WMS/启动流程)及Java后端全家桶(Spring + MyBatis + Redis + Oracle)
累计产出原创技术文章100+篇,文章以源码拆解为特色,被读者评价为"看一篇胜过啃一周文档"


导入语

如果你接触 Python 的第一周就学了 try-except,我敢打赌你一定写过这种代码:

try:do_something()except:pass

是的——“不知道会报什么错,先包起来再说”。新人阶段这么写很正常。但如果到了生产环境你还这么写,问题就大了。我曾经处理过一个线上事故——订单导出功能偶尔丢数据。排查了好久发现根源就是一行except: pass把 PermissionError(文件无法写入)给吞了。数据在内存里算好了,写到磁盘的时候因为权限问题挂了,但因为没有日志,上游系统一直以为写入成功。

不用 try-except 会崩,乱用 try-except 会埋炸弹。这篇文章帮你搞清楚怎么正确地用。


1 ~> Python 的异常体系——一张图看清楚

Python 所有异常的根基是BaseException

BaseException ├─ Exception ← 常见的异常,咱们日常要处理的 │ ├─ ValueError │ ├─ TypeError │ ├─ KeyError │ ├─ IndexError │ ├─ FileNotFoundError │ ├─ ConnectionError │ └─...(你自定义的异常也挂这儿) ├─ KeyboardInterrupt ← Ctrl+C 触发的,不是 Exception 的子类 ├─ SystemExit ← sys.exit()触发的 └─ GeneratorExit ← 生成器关闭时触发的

当你写except:(裸捕获)时,它等价于except BaseException:——连 KeyboardInterrupt 和 SystemExit 都会捕获。这意味着用户按 Ctrl+C 想退出程序?被你拦住了。sys.exit()想优雅退出?也被你拦住了。


2 ~> 最常见的四种错误写法

2.1 错误一:裸捕获except:

# ❌ 极度危险try:result=10/0except:# 连 KeyboardInterrupt 都会捕获pass

危害:按 Ctrl+C 无效,程序卡死只能强制结束进程。SystemExit也被拦截。

修复:

try:result=10/0exceptExceptionase:# 至少限定 Exceptionprint(f"出错:{e}")

2.2 错误二:捕获范围过大except Exception

# ⚠️ 不太好try:data=json.loads(user_input)result=process(data)save_to_db(result)exceptExceptionase:print(f"处理失败:{e}")# 但是不知道是哪一步出了问题

危害:三行代码各自抛不同的异常——json.JSONDecodeErrorValueErrorDatabaseError——全被同一个 except 吞了。你既不知道哪一步出的错,也无法对不同错误采取不同的恢复策略。

# ✅ 精准捕获try:data=json.loads(user_input)exceptjson.JSONDecodeError:return{"error":"JSON 格式有误"}

2.3 错误三:吞掉异常except: pass

# ❌ 生产事故之源try:write_to_file(data)exceptOSError:pass# 文件写失败了,程序一律当成功继续走

这是比重试失败更严重的问题——数据丢失了你都不知道。至少记个日志:

importloggingtry:write_to_file(data)exceptOSErrorase:logging.exception("文件写入失败")raise# re-raise,让上层知道这里出事了

2.4 错误四:在 finally 里写 return

defbad_example():try:return1finally:return2# finally 的 return 会覆盖 try 的 return!print(bad_example())# 输出:2 ← try 的 return 1 被吃了

finally块在 try 的 return 执行之后、函数真正返回之前执行。如果finally里也有return,会覆盖掉 try 的返回值。


3 ~> try/except/else/finally 完整的四块

defrobust_read_file(filename):file=Nonetry:file=open(filename,"r",encoding="utf-8")exceptFileNotFoundError:print(f"文件{filename}不存在")returnNoneexceptPermissionError:print(f"无权限读取{filename}")returnNoneelse:# else:try 块没有异常时才执行(有异常就跳过了)content=file.read()returncontentfinally:# finally:无论是否异常,一定会执行# 这里最适合做清理工作:关文件、释放锁、断开连接iffile:file.close()
什么时候执行最适合做什么
try正常逻辑可能出错的代码放这里
excepttry 中的代码抛出匹配的异常时根据不同类型的异常做不同处理
elsetry 中无异常时把"依赖 try 成功才运行的代码"放这里(和 try 区分开,更清晰)
finally无论如何都会执行(即使有 return)清理资源:关闭文件、释放锁、断开数据库连接

4 ~> 异常链——一个真实场景

当你在 except 里再次抛出异常时,使用raise ... from ...来保留原始上下文:

defload_config(path):try:withopen(path)asf:returnjson.load(f)exceptFileNotFoundErrorase:raiseRuntimeError(f"配置文件{path}读取失败")frome

from e的作用:异常追踪会同时显示RuntimeError和原始FileNotFoundError,而不是把原始异常吃掉。这在排查复杂系统的线上问题时至关重要——你不仅要看到"配置文件加载失败",还要看到"为什么失败(文件不存在)"。


5 ~> 自定义异常

classPaymentError(Exception):"""支付相关的异常基类"""classInsufficientBalanceError(PaymentError):"""余额不足"""def__init__(self,required,available):self.required=required self.available=availablesuper().__init__(f"需要{required}元,余额{available}元")defpay(amount,balance):ifbalance<amount:raiseInsufficientBalanceError(amount,balance)returnbalance-amounttry:pay(100,30)exceptInsufficientBalanceErrorase:print(f"支付失败:{e}")print(f"差额:{e.required-e.available}元")

思考 && 总结

三条铁律:

  1. 永远不要用裸except:至少写except Exception as e。裸捕获会拦截 Ctrl+C 和 sys.exit()。
  2. 捕获要精准。不同类型的异常应该有各自的处理方式。别把所有代码塞一个 try 里,精准异常才能制定精准的恢复策略。
  3. 吞异常至少记日志。except: pass是生产环境下仅次于空指针的危险操作。真的不需要处理的异常也要用logging.exception()记下来。

结尾

各位小伙伴,异常处理到这里就讲完了。感谢阅读!

源码骑士 — Python 全栈 & 系统架构

👀关注:跟博主一起从源码视角深耕底层原理,见证每一次成长

❤️点赞:让优质内容被更多人看见,让知识传递更有力量

收藏:把核心知识点存好,在需要时随时查、随时用

💬评论:分享你的经验或疑问,评论区一起交流避坑

🔄一键四连:不要忘记给博主"一键四连"哦!今日源码拆解达成!

🗡️寄语:技术之路,同行的人会让前路更有方向

结语:异常处理少即是多——精准捕获比大包大揽更安全。下篇讲 import 的机制和那些找不到模块的坑。

http://www.zskr.cn/news/1520509.html

相关文章:

  • 2026优质凤凰办理公司注销业务公司排行哪家好 - 品牌排行榜
  • 3分钟上手MMD Tools:Blender中导入导出MMD模型的完整指南
  • 告别Xftp!AutoDL+JupyterLab一站式搞定YOLOv5文件上传与训练(附数据集管理技巧)
  • 2026年近期诚信的天津物流货代业内推荐:聚焦天津港的可靠伙伴 - 品牌鉴赏官2026
  • 2026 最新 CTF 备赛全流程|零基础分阶段进阶路线 + 刷题完整思路 + 赛场夺分技巧一站式汇总
  • 鸿蒙游戏Runtime解析:Store如何驱动整个游戏世界?
  • BilibiliDown完整指南:如何快速批量下载B站视频
  • [机器学习]Kaggle:CV、Public LB and Private LB
  • 知乎数据获取的终极方案:zhihu-api让你轻松玩转知乎开放数据
  • 深入解析NXP Kinetis SIM模块:时钟管理与外设配置实战指南
  • 2026合肥正规的自动挡陪驾机构联络方式参考 - 品牌排行榜
  • 第十一篇:SpringAI 实战 11|Advisor 机制与对话记忆(ChatMemory):让 AI 拥有“记忆力”
  • 开源5G仿真工具UERANSIM:零成本构建专业5G测试环境终极指南
  • 《Born》第2章:Born 的设计哲学与架构全景
  • 鸿蒙游戏为什么掉帧?60FPS性能优化实战指南
  • 工会刷新思考
  • 众薪广告模式的技术与商业逻辑:公排网络+积分清算的设计思路
  • 基于PLC的电气控制室温湿度自动调节控制系统12(设计源文件+万字报告+讲解)(支持资料、图片参考_降重降ai)
  • 如何让Windows任务栏透明化:TranslucentTB新手终极美化指南
  • QKeyMapper:打破Windows输入限制的免费开源按键映射神器
  • BetterNCM Installer II:让网易云音乐插件管理变得前所未有的简单
  • IRC新手避坑指南:从注册、验证到私聊的完整流程解析(附WeeChat配置)
  • 基于PLC的工业4.0的智能物料分拣与装配系统设计2(设计源文件+万字报告+讲解)(支持资料、图片参考_降重降ai)
  • 3个步骤,让Translumo成为你的游戏外语翻译神器
  • 从芯片到Agent:揭秘AI产业链的财富密码,谁将定义下一轮竞争格局?AI产业链全景图(2026版)
  • NSK MPFD 1602-4 预紧型高刚性滚珠丝杠详解
  • 基于加权稀疏矩阵恢复与加速交替方向乘子法的单通道盲解混响算法(Matlab代码实现)
  • 别再只会plot了!用MATLAB mesh函数给你的数据穿上3D网格外衣(附完整代码)
  • TV Bro电视浏览器:基于Android系统的遥控器优化网页浏览解决方案
  • 基于时频域一阶秩矩阵提升的单通道盲解混响算法(Matlab代码实现)