except exception 不能捕获所有异常,因为其父类 baseexception 才是顶层基类;keyboardinterrupt、systemexit、memoryerror 等直接继承自 baseexception,故会被漏掉。

为什么 except Exception 不能捕获所有异常
因为 Exception 不是 Python 异常体系的顶层基类——BaseException 才是。SystemExit、KeyboardInterrupt、GeneratorExit、MemoryError 等都直接继承自 BaseException,但不继承自 Exception。所以用 except Exception: 会漏掉这些关键信号。
哪些异常会被 except Exception 漏掉
最常见的是用户主动中断(Ctrl+C)和程序退出请求:
-
KeyboardInterrupt:用户按Ctrl+C时抛出,except Exception完全捕获不到 -
SystemExit:调用sys.exit()时触发,同样绕过Exception -
MemoryError虽然罕见,但也属于BaseException子类,不在Exception分支下
真要“捕获所有”,该用 except BaseException 吗
技术上可以,但强烈不建议。原因很实际:
-
SystemExit和KeyboardInterrupt是程序正常控制流的一部分,强行捕获会破坏用户预期(比如无法用Ctrl+C中断卡死脚本) -
MemoryError捕获后往往无资源可用来安全处理,硬兜底反而可能引发更严重问题 - 真正需要“兜底”的场景,通常是日志记录+重新抛出,而不是静默吞掉
推荐做法是明确捕获你预期的异常类型,再加一个 except Exception as e: 做常规兜底,最后用 finally 或 atexit 处理清理逻辑。
一个更稳健的日志兜底写法
如果目标是“不因未预见异常导致程序静默崩溃”,用下面这种结构比盲目捕获 BaseException 更可靠:
try:
main()
except KeyboardInterrupt:
print("\n收到中断信号,正在退出…")
sys.exit(1)
except SystemExit:
raise # 让 sys.exit() 正常生效
except Exception as e:
logger.error("未预期异常", exc_info=True)
raise # 保留原始 traceback,便于调试
关键是:不试图拦截控制类异常,而是让它们走原路径;只对业务逻辑中可能出错的部分做 Exception 级捕获,并确保错误被记录且不掩盖上下文。
真正难处理的从来不是“怎么捕获全部”,而是“哪些不该捕获”——这点容易被忽略,但决定了程序是否可控。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











