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

Python秒表开发问题:按下Esc键无法终止while循环

问题:按下Esc键后秒表循环未停止

我正在尝试用Python开发一款秒表,目前遇到的问题是:当listener返回False时,我的while循环并未停止。

我的代码

from pynput.keyboard import Key, Listener
import time

def pressOn(key):
    x = 'Press: {}'.format(key)
    # 调试用打印
    print(x)
def pressOff(key):
    y = 'Release: {}'.format(key)
    # 调试用打印
    print(y)
    if key == Key.esc:
        return False

t = 0
stop = True
with Listener(on_press = pressOn, on_release = pressOff) as listener:
    while True:
        print(f'it has been {t} seconds')
        t += 1
        time.sleep(1)
        if listener == False:
            break
    listener.join()

print(f'Final time {t} second(s)')

无按键操作时的输出

>>> it has been 0 seconds
>>> it has been 1 seconds
>>> it has been 2 seconds

按下Esc键后的实际输出

在0秒和1秒消息之间按下并释放1和Esc键,之后按其他键无响应,输出如下:

>>> it has been 0 seconds
>>> Press: '1'
>>> Release: '1'
>>> Press: Key.esc
>>> Release: Key.esc
>>> it has been 1 seconds
>>> it has been 2 seconds
>>> it has been 3 seconds
>>> it has been 4 seconds
>>> it has been 5 seconds

期望输出

>>> it has been 0 seconds
>>> Press: '1'
>>> Release: '1'
>>> Press: Key.esc
>>> Release: Key.esc
>>> Final time 1 second(s)

解决方案

问题出在两个核心点:

  1. 错误的停止判断逻辑:if listener == False:完全无效,listener是Listener对象实例,永远不会等于布尔值False,无法通过该条件触发循环终止。
  2. 阻塞式sleep导致响应延迟:time.sleep(1)会让主线程完全阻塞1秒,即使按下Esc,也要等sleep结束才会检查停止条件,导致多执行一次计时循环。

修改后的代码如下:

from pynput.keyboard import Key, Listener
import time

# 定义共享的运行控制标志
running = True

def pressOn(key):
    print(f'Press: {key}')

def pressOff(key):
    global running
    print(f'Release: {key}')
    if key == Key.esc:
        running = False
        return False  # 停止listener线程

t = 0
with Listener(on_press=pressOn, on_release=pressOff) as listener:
    while running:
        print(f'it has been {t} seconds')
        t += 1
        # 拆分长sleep为多次短检查,避免阻塞太久
        for _ in range(10):
            if not running:
                break
            time.sleep(0.1)
    listener.join()

print(f'Final time {t} second(s)')

修改说明

  • 用全局变量running作为循环的控制开关,按下Esc时在pressOff中设置running = False,同时返回False停止listener线程。
  • 将原来的1秒sleep拆分成10次0.1秒的短sleep,每次sleep后检查running状态,确保能及时响应停止指令,避免多走一次完整的计时循环。

内容的提问来源于stack exchange,提问作者ShaggyWaaggy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:43:16