sys.excepthook 是Python解释器处理主线程未捕获异常的回调函数,仅捕获主线程中未被try/except拦截的异常,不处理子线程、协程、SystemExit、KeyboardInterrupt等。

sys.excepthook 是什么,它能捕获哪些异常
sys.excepthook 是 Python 解释器在遇到未被捕获的异常(即“冒泡到顶层”的异常)时调用的回调函数。它只处理主线程中未被 try/except 拦截的异常,**不处理子线程、协程(async/await)、信号中断或 SystemExit/KeyboardInterrupt 默认行为**(除非显式重写)。常见误判是以为它能兜住所有崩溃——其实 KeyboardInterrupt 默认会触发原生退出流程,sys.excepthook 不会自动介入。
如何安全替换默认 excepthook 并保留原始行为
直接赋值 sys.excepthook = my_handler 很容易丢掉原始逻辑(比如 traceback 格式化、stderr 输出),导致错误信息消失或调试困难。推荐做法是封装原钩子:
import sys
import traceback
<p>def my_excepthook(exc_type, exc_value, exc_traceback):</p><h1>先记录日志或上报(可选)</h1><pre class="brush:php;toolbar:false;">print(f"[ERROR] Unhandled {exc_type.__name__}: {exc_value}")
# 再调用原始 hook,确保 traceback 正常打印到 stderr
sys.__excepthook__(exc_type, exc_value, exc_traceback)
sys.excepthook = my_excepthook
- 务必使用
sys.__excepthook__(双下划线),不是sys.excepthook,否则可能递归调用 - 不要在 handler 里抛出新异常,否则解释器会 fallback 到最小化输出(仅显示
Exception ignored) - 若需异步上报(如发 HTTP 请求),必须用同步方式或加超时,避免阻塞进程退出
为什么多线程里 excepthook 不生效
每个线程的未捕获异常默认由 threading.excepthook 处理(Python 3.8+),和 sys.excepthook 完全无关。主线程异常走 sys.excepthook,子线程走独立机制。要统一捕获:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- Python 3.8+:设置
threading.excepthook,类型为threading.ExceptHookArgs对象 - 兼容旧版本:在
Thread(target=...)外层手动包一层try/except,或重写threading.Thread.run - 协程(asyncio):需监听
asyncio.get_event_loop().set_exception_handler(),和sys.excepthook无任何关系
实际部署时最常被忽略的三个点
本地测试看似正常,上线后失效,往往卡在这几个细节:
- 某些打包工具(如 PyInstaller、cx_Freeze)会重置
sys.excepthook,需在入口脚本最顶部立即设置 - 日志框架(如 logging.basicConfig)若配置了
raiseExceptions=False,可能吞掉部分异常,让excepthook根本收不到 -
os._exit()或 C 扩展强制退出会绕过整个 Python 异常机制,excepthook完全不触发——这种退出无法被 Python 层捕获
真正可靠的崩溃防护从来不是只靠一个钩子,而是分层:关键路径加 try/except,顶层设 sys.excepthook 做兜底,再配合外部监控(如 systemd 的 Restart=on-failure 或 Kubernetes 的 liveness probe)。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










