当前位置:首页>python>Python 异常处理:从 try-except 到自定义异常

Python 异常处理:从 try-except 到自定义异常

  • 2026-10-13 08:30:07
Python 异常处理:从 try-except 到自定义异常

写 Python 最怕什么?不是写不出来,而是"跑着跑着突然崩了"。读文件——文件不存在;做除法——分母是 0;调接口——网络断了;解析 JSON——格式不对。程序一崩,用户看到一堆红色报错,看到半夜被叫醒的钉钉消息。异常处理的本质,就是给程序装一套"安全气囊":出事的时候不至于车毁人亡,而是安全停下来,告诉发生了什么。

1

先搞清楚:异常 ≠ 语法错误

很多人把"报错"统称为异常,其实 Python 里的"错"分两种:

类型
什么时候出现
例子
能处理吗
语法错误(SyntaxError)
运行之前,解释器检查代码时
if x > 0
 漏了冒号
❌ 不能,必须改代码
异常(Exception)
运行过程中,逻辑上出了状况
10 / 0
、int("abc")
✅ 可以,用 try-except

语法错误是"写错了",异常是"运行时出了问题"。 异常处理只管后者。

2

try-except:异常处理的最小可用单元

执行逻辑很简单:先执行 try 块里的代码没出问题 → 跳过 except,继续往下走出了问题 → 跳到匹配的 except 块,执行处理逻辑,然后继续往下走一句话: try 是"试试看",except 是"出了问题这么办"。

3

多分支捕获:不同错误,不同应对

实际开发中,一段代码可能触发多种异常。Python 支持用多个 except 分支分别处理:

关键规则:异常匹配从上到下,一旦匹配成功就不再往下走子类异常要写在父类前面,否则父类会把子类全"吞掉"Exception 是几乎所有常规异常的父类,放在最后做兜底

错误写法
正确写法
为什么
except Exception
 放最前面
except Exception
 放最后面
父类在前会吞掉所有子类异常
except TypeError, ValueError:except (TypeError, ValueError):
Python 3 必须用元组加括号

4

else 和 finally:补全流程控制

完整的异常处理结构有四个关键字:try → except → else → finally

每个关键字的执行时机:

关键字
什么时候执行
典型用途
try
始终执行(第一个)
放可能出错的代码
except
只在匹配到异常时执行
处理对应类型的异常
else
只在没有异常时执行
放"成功时才做"的逻辑
finally无论如何都执行
清理资源:关文件、断连接、释放锁

完整示例:

一句话: else 是"没出事就做这个",finally 是"不管出不出事都要收尾"。

5

finally 的三个"反直觉"行为

finally 是异常处理里最容易踩坑的部分,有三个行为必须记住:

5.1 except 里有 return,finally 仍然执行

finally 在 return 之前执行。

5.2 finally 里也有 return → finally 的返回值"赢"

finally 的 return 会覆盖 try 的 return。 这是经典面试题,也是生产环境里的隐形地雷。

5.3 finally 里抛新异常 → 原始异常被吞掉

结论:finally 里只做清理,不要 return,不要 raise。

6

raise:主动抛出异常

异常处理不只是"接住"异常,有时候你需要主动抛出异常。

6.1 基础用法

什么时候用 raise? 当 Python 内置异常无法表达你的业务规则时。比如"密码长度不够"——Python 不会自动检查这种事,你得自己 raise。

6.2 裸 raise:重新抛出当前异常

典型场景: 先记日志,再让上层处理。裸 raise 保留原始异常类型和完整的 traceback。

6.3 异常链:raise ... from ...

用 from 链接原始异常和新异常,traceback 里会显示完整的因果链:

调试时救命的功能,别省掉。

7

自定义异常:让错误信息"说人话"

内置异常(ValueError、TypeError)是通用的,但业务场景需要更精确的错误语义。 

7.1 基本写法
7.2 构建异常层次结构

分层捕获的好处:

设计原则:自定义异常必须继承 Exception,不要直接继承 BaseException类名以 Error 结尾异常类里只放描述错误的信息,不要塞业务逻辑继承层次不超过 4-5 层

8

实战场景:文件操作的完整异常处理

更好的写法:用 with 语句自动管理资源

with 语句自动处理了 finally 的关闭逻辑,代码更简洁也更安全。文件操作用 with,数据库连接用 contextmanager,网络请求用 session.close()。

9

10 个常见坑点,踩一个痛一次

#
坑
后果
正确做法
1
裸 except: 不带类型
连 SystemExit 和 KeyboardInterrupt 都吞了
至少写 except Exception:
2
except Exception
 放最前面
后面的 except 全部失效
具体异常在前,通用异常在后
3
except (TypeError, ValueErrr)
 少括号
Python 3 语法错误
必须加括号写成元组
4
try 块写太大
意外捕获了不该捕获的异常
try 里只放可能出错的那几行
5
except 里只 print 不 raise
错误被吞掉,下游完全不知道出了问题
记日志后 raise 或返回明确的错误信息
6
finally 里 return
覆盖了 try/except 的返回值
finally 只做清理,不 return
7
finally 里 raise
原始异常被新异常吞掉
finally 里不抛异常
8
自定义异常继承 BaseException
可能干扰 SystemExit 等系统级异常
始终继承 Exception
9
不用异常链(from)
调试时丢失原始错误上下文
raise NewError(...) from original_exc
10
用 return None 代替 raise
调用者不知道失败了,错误悄悄传播
用 raise 让调用者必须处理

100

速查表

一句话总结: try-except 是给程序装安全气囊,else 是"平安到达的奖励",finally 是"不管怎样都要系好安全带",raise 是"主动按下紧急制动按钮"。

往期推荐

跨PC仿真实现S7通信:两台电脑就能搭出分布式调试环境

三菱FX5U温控实战:从零搭建一套工业加热系统

S7-1500自动分拣加工系统:从架构到程序

从传感器到气缸,手把手教写出能跑的程序

点胶轨迹实操:多轴插补从入门到良品率99.9%

S7-1200运动控制轴,从0到1玩转工艺对象,别再对着脉冲发呆了

三菱FR-D700变频器参数设置与实操指南——从面板操作到现场调试

用SCL写S7-1200 Modbus通讯,少走半年弯路

升降控制系统程序架构设计及组态——从硬件选型到安全联锁

S7-1200定时器四种工作类型+时间数据类型转换

PLC常见故障原因及处理:老电工30年经验的排查铁律

西门子触摸屏弹窗公共调用,一个弹窗控制所有设备,有会的吗?

S7-1200 FB功能块封装调用 & UDT用户数据类型创建

PLC调试顺序:离线检查→手动调试→自动调试→故障模拟,一步都不能少

从HMI到MES,把数据链路打通

西门子单站控制:从I/O分配到手动自动切换

S7-1200 Modbus通讯功能块优化封装:从"能用"到"好用"的进阶之路

工控人绕不开的通讯第一课 (Modbus数据采集

S7-1200模拟量之FC:写一次,调用100次,这才是正确的打开方式

当1500搞不定时,该上T了

当PLC不够用时,让C++来帮忙

CPU 1515SP PC开放式控制器:PLC和PC,终于不用分开买了

最新文章

随机文章