应避免使用 except BaseException,因为它会静默捕获 KeyboardInterrupt、SystemExit、MemoryError 和 GeneratorExit 等系统级异常,导致无法中断程序、退出失败、内存崩溃或资源泄漏;正确做法是仅用 except Exception 或显式单独处理特定系统异常。

为什么 except BaseException 会吞掉 Ctrl+C
直接写 except BaseException: 会捕获 KeyboardInterrupt,导致用户按 Ctrl+C 无法中断程序。这不是“没反应”,而是异常被静默吃掉了——Python 收到中断信号后抛出 KeyboardInterrupt,但它立刻被你的 except BaseException: 捕获,后续逻辑照常执行。
- 真实表现:终端光标还在闪,进程没退出,但你已经没法中止它了
- 调试时尤其危险:你以为脚本卡死,其实是被异常处理器拦住了退出路径
-
KeyboardInterrupt继承自BaseException,但不继承自Exception,所以except Exception:不会干扰它
sys.exit() 为什么会失效
sys.exit() 内部实际是抛出 SystemExit 异常,而 SystemExit 也直接继承自 BaseException。一旦你用了 except BaseException:,这个退出信号就被拦截,程序不会终止,而是继续往下走。
- 模块协作场景下后果严重:比如你调用了一个依赖
sys.exit()做清理的第三方库,结果它“退出失败”,资源没释放,状态不一致 - 测试时容易漏掉:单元测试里用
assertRaises(SystemExit)会失败,因为异常根本没冒泡出来 - 替代方案不是“修复捕获”,而是根本别捕获它——让
SystemExit按原设计传播
MemoryError 和 GeneratorExit 也不该被常规捕获
MemoryError 出现时,Python 已经处于内存耗尽边缘;GeneratorExit 是生成器被显式关闭的内部信号。两者都属于运行环境级事件,不是业务逻辑错误。
-
MemoryError被捕获后强行继续执行,大概率触发二次崩溃,且无有效恢复手段 -
GeneratorExit被捕获会导致生成器协议破坏,finally块可能不执行,资源泄漏风险高 - 它们和
KeyboardInterrupt、SystemExit一起被设计为“不可忽略”的退出点,绕过它们等于绕过 Python 的控制流契约
except Exception: 才是安全的兜底边界
except Exception: 排除了所有 BaseException 的非 Exception 子类,只覆盖业务运行中真正可能出错的部分:网络超时、键不存在、类型错误、权限拒绝等。这才是可控、可记录、可重试的错误范围。
- 它能捕获
requests.exceptions.RequestException、ValueError、PermissionError等绝大多数实际问题 - 如果真要处理系统级异常,必须显式单独写,例如
except KeyboardInterrupt:,并明确做清理或重新抛出 - 空
except Exception:同样危险——至少加一行logging.exception("unhandled exception")
真正难的是判断哪些错误该被捕获、哪些该让程序停住。系统级异常不是“没捕获到”,而是“不该捕获”——它们的存在本身就是在告诉你:现在该停了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











