Ctrl+C触发的是KeyboardInterrupt异常,它继承自BaseException而非Exception,因此except BaseException会拦截该异常导致无法中断程序;而except Exception则安全兜底,只捕获业务异常,保留Ctrl+C的默认中断行为。

Ctrl+C本质是KeyboardInterrupt异常
你在终端按 Ctrl+C,Python 并不是被“强制杀死”,而是操作系统向进程发送了 SIGINT 信号;Python 解释器收到后,会主动抛出一个 KeyboardInterrupt 实例。这个异常类型直接继承自 BaseException,和 Exception 是平级关系,**不归 Exception 管**。
except BaseException: 会吞掉KeyboardInterrupt
当你写 except BaseException:(或等价的裸 except:),你等于告诉 Python:“所有从 BaseException 派生的东西,我全接住”。而 KeyboardInterrupt 正好在此范围内——它一冒出来,立刻被这个 except 拦下,后续的默认中断逻辑(退出程序、打印 traceback)就再没机会执行。
常见表现包括:
- 按 Ctrl+C 后光标卡住,无响应,必须用
kill -9强杀 - 程序看似“还在跑”,但实际已失去控制权
- 日志里看不到任何中断痕迹,排查时误以为是死锁
为什么except Exception: 是安全的兜底
Exception 是 BaseException 的子类,但它**刻意排除了 KeyboardInterrupt、SystemExit、GeneratorExit 这三个系统级控制流异常**。这是 Python 的设计契约:
-
except Exception:只捕获业务运行错误(如ValueError、ConnectionError、FileNotFoundError) -
KeyboardInterrupt仍按原路径向上冒泡,最终由解释器处理——也就是你熟悉的“Traceback interrupted”并退出 - 这样既保住了异常兜底能力,又没破坏用户对进程的基本控制权
唯一该用BaseException的场景极少见
正常业务代码里,你不该捕获 BaseException。唯一合理用途是实现底层基础设施,比如:
- 自研的 REPL 或调试器,需要完全接管所有退出信号
- 测试框架中模拟“进程彻底崩溃”的边界行为
- 嵌入式 Python 解释器的宿主环境做统一信号路由
普通脚本、Web 服务、爬虫、数据处理任务——全都应该用 except Exception:,且至少记录日志,不能只写 pass。真正容易被忽略的是:哪怕你写了 except Exception:,如果外层还有个裸 except: 或 except BaseException:,它依然会把 KeyboardInterrupt 吞掉。检查整个调用栈里的 try 块,比检查单个 except 更重要。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











