文章目录Python 异常处理你写的 try-except 可能比不写更危险导入语1 ~ Python 的异常体系——一张图看清楚2 ~ 最常见的四种错误写法2.1 错误一裸捕获 except:2.2 错误二捕获范围过大 except Exception2.3 错误三吞掉异常 except: pass2.4 错误四在 finally 里写 return3 ~ 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 所有异常的根基是BaseExceptionBaseException ├─ Exception ← 常见的异常咱们日常要处理的 │ ├─ ValueError │ ├─ TypeError │ ├─ KeyError │ ├─ IndexError │ ├─ FileNotFoundError │ ├─ ConnectionError │ └─...你自定义的异常也挂这儿 ├─ KeyboardInterrupt ← CtrlC 触发的不是 Exception 的子类 ├─ SystemExit ← sys.exit()触发的 └─ GeneratorExit ← 生成器关闭时触发的当你写except:裸捕获时它等价于except BaseException:——连 KeyboardInterrupt 和 SystemExit 都会捕获。这意味着用户按 CtrlC 想退出程序被你拦住了。sys.exit()想优雅退出也被你拦住了。2 ~ 最常见的四种错误写法2.1 错误一裸捕获except:# ❌ 极度危险try:result10/0except:# 连 KeyboardInterrupt 都会捕获pass危害按 CtrlC 无效程序卡死只能强制结束进程。SystemExit也被拦截。修复try:result10/0exceptExceptionase:# 至少限定 Exceptionprint(f出错{e})2.2 错误二捕获范围过大except Exception# ⚠️ 不太好try:datajson.loads(user_input)resultprocess(data)save_to_db(result)exceptExceptionase:print(f处理失败:{e})# 但是不知道是哪一步出了问题危害三行代码各自抛不同的异常——json.JSONDecodeError、ValueError、DatabaseError——全被同一个 except 吞了。你既不知道哪一步出的错也无法对不同错误采取不同的恢复策略。# ✅ 精准捕获try:datajson.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 里写 returndefbad_example():try:return1finally:return2# finally 的 return 会覆盖 try 的 returnprint(bad_example())# 输出2 ← try 的 return 1 被吃了finally块在 try 的 return 执行之后、函数真正返回之前执行。如果finally里也有return会覆盖掉 try 的返回值。3 ~ try/except/else/finally 完整的四块defrobust_read_file(filename):fileNonetry:fileopen(filename,r,encodingutf-8)exceptFileNotFoundError:print(f文件{filename}不存在)returnNoneexceptPermissionError:print(f无权限读取{filename})returnNoneelse:# elsetry 块没有异常时才执行有异常就跳过了contentfile.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}读取失败)fromefrom e的作用异常追踪会同时显示RuntimeError和原始FileNotFoundError而不是把原始异常吃掉。这在排查复杂系统的线上问题时至关重要——你不仅要看到配置文件加载失败还要看到为什么失败文件不存在。5 ~ 自定义异常classPaymentError(Exception):支付相关的异常基类classInsufficientBalanceError(PaymentError):余额不足def__init__(self,required,available):self.requiredrequired self.availableavailablesuper().__init__(f需要{required}元余额{available}元)defpay(amount,balance):ifbalanceamount:raiseInsufficientBalanceError(amount,balance)returnbalance-amounttry:pay(100,30)exceptInsufficientBalanceErrorase:print(f支付失败{e})print(f差额{e.required-e.available}元)思考 总结三条铁律永远不要用裸except:。至少写except Exception as e。裸捕获会拦截 CtrlC 和 sys.exit()。捕获要精准。不同类型的异常应该有各自的处理方式。别把所有代码塞一个 try 里精准异常才能制定精准的恢复策略。吞异常至少记日志。except: pass是生产环境下仅次于空指针的危险操作。真的不需要处理的异常也要用logging.exception()记下来。结尾各位小伙伴异常处理到这里就讲完了。感谢阅读源码骑士 — Python 全栈 系统架构关注跟博主一起从源码视角深耕底层原理见证每一次成长❤️点赞让优质内容被更多人看见让知识传递更有力量⭐收藏把核心知识点存好在需要时随时查、随时用评论分享你的经验或疑问评论区一起交流避坑一键四连不要忘记给博主一键四连哦今日源码拆解达成️寄语技术之路同行的人会让前路更有方向结语异常处理少即是多——精准捕获比大包大揽更安全。下篇讲 import 的机制和那些找不到模块的坑。