避开 Python 异常处理常见坑:正确捕获与处理异常
我见太多人异常处理用错。或许你也中招。以下场景耳熟吗?
写代码时知道调用库可能抛异常,但记不清具体哪个。此时极易用“捕获一切”块图省事继续写业务逻辑。
目录
最坏写法
最糟是裸 except: 捕获一切:
try:
...
except:
pass
危害:
1. 完全不知还可能抛出何种异常。
2. 用 pass 静默吞掉异常,等于埋雷。
更甚者,裸 except 等同 except BaseException,连 KeyboardInterrupt (Ctrl+C)、SystemExit、NameError 全捕获!导致如下代码无法正常中断:
from time import sleep
while True:
try:
print("Try and stop me")
sleep(1)
except:
print("Don't.. stop.. me now!")
亲测可行:只能关终端或 kill 进程才能停。
稍好但仍不推荐的全捕获
用 except Exception 虽仍属偷懒大网捕鱼,但至少能正常响应中断信号:
from time import sleep
while True:
try:
print("Try and stop me")
sleep(1)
except Exception:
print("Ok I'll stop!")
为何?所有异常继承自 BaseException。文档规定:except 子句指定类时,自动捕获其子类。裸 except 即 except BaseException,故全捕获。
而 Exception 类定义为:“所有内置非系统退出异常均派生自此。用户自定义异常亦应派生自此。”故 KeyboardInterrupt 等系统级异常不在其列。
更坑人的情况
调用 os.getcwd() 手滑写成 os.getcdw():
import os
try:
working_dir = os.getcdw()
print(working_dir)
except:
print('error')
因 os.getcdw 不存在,抛 NameError。裸 except 捕获并打印 'error',程序继续跑,拼写错误隐匿不发。改用 except Exception 也救不了——NameError 继承自 BaseException 而非 Exception!
第一招并非万能药。那该怎么办?
只捕获你能处理的
异常处理金句:catch what you can handle。开发者常想就地处理异常,但往往应让异常冒泡至真正能处理的层级。
例:文本编辑器打开加载文件的 OpenFile 类。用户请求打开不存在文件,可就地处理,也可向上抛。
此处向上抛更妥:OpenFile 无法判断异常对调用者严重程度。调用者可多策应对:
• 新建同名文件继续
• 因必须有文件而弹错告知用户
决策权不在 OpenFile。
异常是否必须全抛?否。OpenFile 可自处理 TimeoutError:重试几次不打扰调用者。这是它能处理的异常,捕获重试合理。
结论
绝不捕获超出处理能力的异常。裸 except 是 Bug 温床与不可预测代码根源。铭记:只捕获你能处理的。
按此信条写代码,裸 except 即破坏规则。请停止滥用。练习:回顾旧代码,用新认知重构改进!
Python
- 精通 CMMS 培训:激活团队与强化留存的实战框架
- 招聘季来袭:后疫情时代应对申请人激增的四大策略
- 精通Python运算符:全面指南
- 精通 Python 错误与内置异常
- 精通 Python 自定义异常:实战指南
- Python 获取当前日期和时间:实用指南
- Python print() 函数完全指南:基础用法、空行打印与自定义结束符
- Python 字典增删改查与嵌套操作实战指南
- Python print 不换行:掌握 end 参数及其他技巧
- Python 计算平均值:从循环到 NumPy 的四种实战方法
- Python 异常处理全攻略:从入门到精通
- 精通 Java 多异常捕获:单 catch 块处理多异常