You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python秒表程序中KeyboardInterrupt异常未按预期工作的原因与解决办法

Python秒表KeyboardInterrupt异常退出问题分析

问题根因

初始递归版本问题

每次选择恢复计时时,代码在异常处理分支内递归调用start_chronometer函数,每恢复一次调用栈就多嵌套一层。每层的try-except仅能捕获当前层计时循环的中断信号,多次触发中断后一旦某一层选择退出,就会逐层返回上层栈,所有上层函数会直接结束,看起来就像后续语句未执行。同时递归层级过多还可能触发Python默认的递归深度限制报错。

修改后循环版本问题

虽然替换递归为外层循环,但try-except仅包裹了内层的计数循环,存在两个捕获盲区:

  • 询问是否恢复的input调用不在try块覆盖范围内,等待输入时触发中断会直接抛出未捕获异常
  • 内层循环结束、外层循环重启的间隙触发中断,也没有对应的捕获逻辑
    同时原计时循环没有任何休眠逻辑,CPU占满的状态下会导致Python解释器无法及时响应中断信号,多次快速触发中断会直接抛到最外层导致程序退出。

修复后可运行代码

import time

def start_chronometer():
    total_passed = 0.0
    while True:
        start_time = time.time()
        try:
            # 计时循环加短休眠,降低CPU占用同时保证中断响应及时
            while True:
                time.sleep(0.1)
        except KeyboardInterrupt:
            # 累计本次计时时长
            total_passed += time.time() - start_time
            # 输入阶段也加中断捕获
            while True:
                try:
                    choice = input('是否继续计时? y-是 / n-否: ').strip().upper()
                    if choice in ('Y', 'N'):
                        break
                    print('输入无效,请输入y或者n')
                except KeyboardInterrupt:
                    # 输入阶段触发中断默认按退出处理
                    choice = 'N'
                    break
            if choice == 'N':
                break
    # 格式化输出时长
    if total_passed >= 3600:
        print(f'总计时长:{total_passed / 3600:.2f} 小时')
    elif total_passed >= 60:
        print(f'总计时长:{total_passed / 60:.2f} 分钟')
    else:
        print(f'总计时长:{total_passed:.2f} 秒')

if __name__ == "__main__":
    start_chronometer()

修复说明

  • 移除递归实现,改用单层循环累计计时时长,避免栈帧嵌套问题
  • 计时循环增加0.1秒短休眠,既不影响计时精度,又能降低CPU占用,同时保证Python解释器可以及时响应中断信号
  • 输入选择阶段新增KeyboardInterrupt捕获,避免等待输入时触发中断直接退出
  • 所有核心逻辑的异常都在同一层处理,不存在异常向上层栈抛出导致意外退出的问题

内容的提问来源于stack exchange,提问作者gerson chadi junior

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 03:54:01