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

Python脚本无法按预期循环运行问题求助(含pynput代码)

问题描述

编写了如下使用pynput库的Python脚本,无论是直接用Python3运行还是通过PyInstaller打包后运行,脚本都无法按预期持续循环,且无任何报错信息:

import time
from pynput import keyboard
from pynput.keyboard import Key, Listener

STATUS=False
COMBINATION={keyboard.Key.esc, keyboard.Key.alt}

# The currently active modifiers
current = set()

def on_press(key):
    if key in COMBINATION:
        current.add(key)
        if all(k in current for k in COMBINATION):
            STATUS = False
    if key == keyboard.Key.esc:
        # Stop listener
        STATUS = True

def on_release(key):
    try:
        current.remove(key)
    except KeyError:
        pass

def hp(delay):
    keyboard.press(Key.f1)
    keyboard.release(Key.f1)
    time.sleep(delay)

def cp():
    keyboard.press(Key.f2)
    keyboard.release(Key.f2)

def main():
    with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
            listener.join()
    while True:
        while STATUS:
            for i in range(3):
                hp(0.5)
            cp()
问题排查与修复

核心问题分析

  1. 全局变量未正确引用:STATUS是全局变量,但on_press函数中直接赋值时,Python会将其视为局部变量,导致外部循环无法感知状态变化。
  2. Listener阻塞主线程:listener.join()会一直阻塞主线程,直到Listener停止,后面的while True循环永远不会执行。
  3. 按键逻辑冲突:按下esc键时同时触发两个矛盾逻辑:既设置STATUS=True,又因esc在COMBINATION中设置STATUS=False。
  4. 按键模拟方式不安全:直接调用keyboard.press/release可能引发线程安全问题,因为Listener本身运行在独立线程中。

修复后的代码

import time
from pynput import keyboard
from pynput.keyboard import Key, Listener
import threading

# 全局状态变量
STATUS = False
COMBINATION = {keyboard.Key.esc, keyboard.Key.alt}
current = set()

def on_press(key):
    global STATUS
    if key in COMBINATION:
        current.add(key)
        # 同时按下alt+esc时停止循环
        if all(k in current for k in COMBINATION):
            STATUS = False
    # 单独按下esc时启动循环
    elif key == keyboard.Key.esc:
        STATUS = True

def on_release(key):
    try:
        current.remove(key)
    except KeyError:
        pass

def hp(delay):
    # 使用Controller安全模拟按键
    with keyboard.Controller() as ctrl:
        ctrl.press(Key.f1)
        ctrl.release(Key.f1)
    time.sleep(delay)

def cp():
    with keyboard.Controller() as ctrl:
        ctrl.press(Key.f2)
        ctrl.release(Key.f2)

def loop_task():
    """在子线程中运行循环逻辑,避免阻塞Listener"""
    while True:
        while STATUS:
            for _ in range(3):
                hp(0.5)
            cp()
        time.sleep(0.1)  # 降低空循环的CPU占用

def main():
    # 启动循环子线程,设置为守护线程随主线程退出
    threading.Thread(target=loop_task, daemon=True).start()
    
    # 启动键盘监听器,主线程保持监听
    with Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()

if __name__ == "__main__":
    main()

修复说明

  • 全局变量绑定:通过global STATUS声明,确保函数内修改的是全局状态变量。
  • 线程分离:将循环逻辑放到独立子线程中,避免被Listener的阻塞调用卡住。
  • 逻辑修正:区分单独按esc(启动循环)和alt+esc(停止循环)的操作,消除逻辑冲突。
  • 安全按键模拟:使用keyboard.Controller()处理按键模拟,避免跨线程操作的潜在问题。
  • 性能优化:状态未激活时添加短延时,减少空循环对CPU的消耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 10:21:03