如何通过按键来终止 while 循环?

2025-01-22 08:45:00
admin
原创
91
摘要:问题描述:我正在使用 while 循环读取串行数据并将其写入 csv 文件。我希望用户能够在他们觉得已经收集到足够的数据后终止 while 循环。while True: #do a bunch of serial stuff #if the user presses the 'esc' or...

问题描述:

我正在使用 while 循环读取串行数据并将其写入 csv 文件。我希望用户能够在他们觉得已经收集到足够的数据后终止 while 循环。

while True:
    #do a bunch of serial stuff

    #if the user presses the 'esc' or 'return' key:
        break

我已经使用 opencv 做过类似的事情,但它似乎无法在这个应用程序中工作(而且我真的不想只是为了这个功能而导入 opencv)...

        # Listen for ESC or ENTER key
        c = cv.WaitKey(7) % 0x100
        if c == 27 or c == 10:
            break

那么。我怎样才能让用户跳出循环?

另外,我不想使用键盘中断,因为脚本需要在 while 循环终止后继续运行。


解决方案 1:

最简单的方法就是用通常的方法Ctrl-C(SIGINT)来中断它。

try:
    while True:
        do_something()
except KeyboardInterrupt:
    pass

由于Ctrl-C会引起KeyboardInterrupt引发,因此只需在循环外捕获它并忽略它。

解决方案 2:

有一种解决方案不需要非标准模块并且 100%可移动:

import _thread

def input_thread(a_list):
    raw_input()             # use input() in Python3
    a_list.append(True)
    
def do_stuff():
    a_list = []
    _thread.start_new_thread(input_thread, (a_list,))
    while not a_list:
        stuff()

解决方案 3:

以下代码对我有用。它需要 openCV(导入 cv2)。

代码由一个无限循环组成,该循环不断寻找按下的键。在这种情况下,当按下“q”键时,程序结束。可以按下其他键(在此示例中为“b”或“k”)来执行不同的操作,例如更改变量值或执行函数。

import cv2

while True:
    k = cv2.waitKey(1) & 0xFF
    # press 'q' to exit
    if k == ord('q'):
        break
    elif k == ord('b'):
        # change a variable / do something ...
    elif k == ord('k'):
        # change a variable / do something ...

解决方案 4:

对于 Python 3.7,我复制并更改了 user297171 的非常好的答案,因此它可以在我测试的 Python 3.7 中的所有场景中起作用。

import threading as th

keep_going = True
def key_capture_thread():
    global keep_going
    input()
    keep_going = False

def do_stuff():
    th.Thread(target=key_capture_thread, args=(), name='key_capture_thread', daemon=True).start()
    while keep_going:
        print('still going...')

do_stuff()

更新

上述input()停止运行的方法在较新版本的 Linux 上不再有效(由于 input() 不是线程特定的,所以设计如此),因此这里提供另一种方法:

from pynput import keyboard

def do_stuff():
    keep_going=keyboard.Listener(lambda key: False if key==keyboard.Key.enter else True)
    keep_going.start()
    while keep_going.is_alive():
        print('still going...')

do_stuff()

这里的键是 Enter,但您可以将其更改keyboard.Key.enter为任何其他键来设置任何键,例如 esc 或 q。

解决方案 5:

pip install keyboard

import keyboard

while True:
    # do something
    if keyboard.is_pressed("q"):
        print("q pressed, ending loop")
        break

解决方案 6:

这是一个对我有用的解决方案。从这里和其他地方的帖子中得到了一些想法。循环不会结束,直到按下定义的键(abortKey)。循环尽可能快地停止,并且不会尝试运行到下一个迭代。

from pynput import keyboard
from threading import Thread
from time import sleep

def on_press(key, abortKey='esc'):    
    try:
        k = key.char  # single-char keys
    except:
        k = key.name  # other keys    

    print('pressed %s' % (k))
    if k == abortKey:
        print('end loop ...')
        return False  # stop listener

def loop_fun():
    while True:
        print('sleeping')
        sleep(5)
        
if __name__ == '__main__':
    abortKey = 't'
    listener = keyboard.Listener(on_press=on_press, abortKey=abortKey)
    listener.start()  # start to listen on a separate thread

    # start thread with loop
    Thread(target=loop_fun, args=(), name='loop_fun', daemon=True).start()

    listener.join() # wait for abortKey

解决方案 7:

pyHook 可能会有帮助。http ://sourceforge.net/apps/mediawiki/pyhook/index.php? title=PyHook_Tutorial#tocpyHook%5FTutorial4

查看键盘钩子;这是更为通用的——如果您想要特定的键盘交互而不是仅仅使用 KeyboardInterrupt。

此外,一般来说(取决于您的使用情况),我认为仍然可以使用 Ctrl-C 选项来终止您的脚本是有意义的。

另请参阅上一个问题:在 Python 中检测按下了哪些键

解决方案 8:

从这个线程进入兔子洞后,我找到了这个,可以在 Win10 和 Ubuntu 20.04 上运行。我想要的不仅仅是杀死脚本,还要使用特定的键,它必须在 MS 和 Linux 上都能工作。

import _thread
import time
import sys
import os

class _Getch:
    """Gets a single character from standard input.  Does not echo to the screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()

class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        msvcrt_char = msvcrt.getch()
        return msvcrt_char.decode("utf-8")

def input_thread(key_press_list):
    char = 'x'
    while char != 'q': #dont keep doing this after trying to quit, or 'stty sane' wont work
        time.sleep(0.05)
        getch = _Getch()
        char = getch.impl()
        pprint("getch: "+ str(char))
        key_press_list.append(char)

def quitScript():
    pprint("QUITTING...")
    time.sleep(0.2) #wait for the thread to die
    os.system('stty sane')
    sys.exit()

def pprint(string_to_print): #terminal is in raw mode so we need to append 

    print(string_to_print, end="
")

def main():
    key_press_list = []
    _thread.start_new_thread(input_thread, (key_press_list,))
    while True:
        #do your things here
        pprint("tick")
        time.sleep(0.5)

        if key_press_list == ['q']:
            key_press_list.clear()
            quitScript()

        elif key_press_list == ['j']:
            key_press_list.clear()
            pprint("knock knock..")

        elif key_press_list:
            key_press_list.clear()

main()

解决方案 9:

我修改了 rayzinnz 的答案,用特定键结束脚本,在本例中是 Esc 键

import threading as th
import time
import keyboard

keep_going = True
def key_capture_thread():
    global keep_going
    a = keyboard.read_key()
    if a== "esc":
        keep_going = False


def do_stuff():
    th.Thread(target=key_capture_thread, args=(), name='key_capture_thread', daemon=True).start()
    i=0
    while keep_going:
        print('still going...')
        time.sleep(1)
        i=i+1
        print (i)
    print ("Schleife beendet")


do_stuff()

解决方案 10:

总是有的sys.exit()

Python 核心库中的系统库有一个退出函数,在原型设计时非常方便。代码如下:

import sys

while True:
    selection = raw_input("U: Create User
Q: Quit")
    if selection is "Q" or selection is "q":
        print("Quitting")
        sys.exit()
    if selection is "U" or selection is "u":
        print("User")
        #do_something()

解决方案 11:

这是我使用线程和标准库找到的解决方案,

循环一直进行,直到按下一个键,将

按下的键作为单个字符串返回

,适用于 Python 2.7 和 3

import thread
import sys

def getch():
    import termios
    import sys, tty
    def _getch():
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch
    return _getch()

def input_thread(char):
    char.append(getch())

def do_stuff():
    char = []
    thread.start_new_thread(input_thread, (char,))
    i = 0
    while not char :
        i += 1

    print "i = " + str(i) + " char : " + str(char[0])

do_stuff()

解决方案 12:

接受的答案KeyboardInterrupt对我来说不可靠,但以下使用pyinputq的解决方案有效(Python 3.10,Linux)。当按下时,while 循环结束:

from pynput.keyboard import Listener  # pip install pynput

keyboard_quit = False

def keyboard_handler(key):
    global keyboard_quit
    if hasattr(key, 'char') and key.char == 'q':
        keyboard_quit = True

keyboard_listener = Listener(on_press=keyboard_handler)
keyboard_listener.start()  # Non-blocking

while not keyboard_quit:
    # Do something

解决方案 13:

这可能有助于安装 pynput --pip install pynput

from pynput.keyboard import Key, Listener
def on_release(key):
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
while True:
    with Listener(
            on_release=on_release) as listener:
        listener.join()
    break 

解决方案 14:

这是一个简单的 Windows 解决方案,可以安全地结束当前迭代然后退出。我将其与一个计数器示例一起使用,该示例使用“Esc”键中断循环并退出。它使用msvcrt包中的kbhit()和getch()函数。仅出于便利原因(设置事件之间的时间延迟)调用时间包。

import msvcrt, time

print("Press 'Esc' to stop the loop...")
x = 0
while True:
    x += 1
    time.sleep(0.5)
    print(x)
    
    if msvcrt.kbhit():
        if msvcrt.getch() == b'x1b':
            print("You have pressed Esc! See you!")
            time.sleep(2)    
            break

如果按键正在等待读取,则kbhit()函数返回 True

getch()函数读取按键并将结果字符作为字节字符串返回。它可以与任何键一起使用

b''是 'Esc' 键的字节字符串字符。

解决方案 15:

这是另一个使用的例子threading.Event,无需捕获SIGINTCtrl+c)。

正如 @Atcold 在已接受答案下方的评论中提到的那样,按下Ctrl+c循环可能会中断长时间运行的操作并使其处于未定义状态。当长时间运行的操作来自您正在调用的库时,这可能会特别烦人。

在下面的例子中,用户需要按下q然后按下Enter。如果你想立即捕获按键,你需要类似这个答案_Getch()的内容。

import time
from threading import Thread, Event


def read_input(q_entered_event):
    c = input()
    if c == "q":
        print("User entered q")
        q_entered_event.set()


def do_long_running_stuff():
    q_pressed_event = Event()
    input_thread = Thread(target=read_input,
                          daemon=True,
                          args=(q_pressed_event,))
    input_thread.start()
    while True:
        print("I am working ...")
        time.sleep(1)
        if q_pressed_event.is_set():
            break
    
    print("Process stopped by user.")


if __name__  == "__main__":
    do_long_running_stuff()

解决方案 16:

from time import sleep
from threading import Thread
import threading

stop_flag = 0
    
    def Wait_Char():
        global stop_flag
        v = input("Enter Char")
        if(v == "z"):
            stop_flag = 1
    
    
    def h():
        while(True):
            print("Hello Feto")
            time.sleep(1)
            if(stop_flag == 1):
                break
    
    
    thread1 = Thread(target=Wait_Char)
    thread2 = Thread(target=h)
    thread1.start()
    thread2.start()
    print("threads finished...exiting")

这不是最好的方法,但它可以完成你想要的工作

运行2个线程,一个等待你想要停止循环的键

(Wait_Char方法)

,一个用于循环

(H方法)

,并且两个线程都看到一个全局变量stop_flag,它控制停止过程当我按下z时停止

解决方案 17:

from pynput import keyboard

def on_press(key):
    if key == keyboard.Key.esc:
        return False

i = 0
with keyboard.Listener(on_press=on_press) as listener:
    # Your infinite loop
    while listener.running:
        print(i)
        i=i+1
print("Done")

有用 ...

解决方案 18:

您可以在 python 3.11 中使用键盘。

pip install keyboard

回答:

from keyboard import add_hotkey, remove_hotkey
from time import sleep

def break_loop():
    global stop
    stop = True

add_hotkey("q", break_loop)
stop = False
while True:
    print("Do something...")
    sleep(1)
    if stop == True:
        break
remove_hotkey("q")

如果你在工作中睡眠充足,并且有 10 秒的睡眠时间,你可以这样做:

from keyboard import add_hotkey, remove_hotkey
from time import sleep

def break_loop():
    global stop
    stop = True

add_hotkey("q", break_loop)
stop = False
while True:
    print("Do something...")
    for i in range(10): # Waiting
        sleep(1) # Split 10 seconds for fast break
        if stop == True: # First break
            break
    if stop == True: # Second break
        break
remove_hotkey("q")

解决方案 19:

对于仍在寻找答案的人来说,对我来说最简单、最简短、最强大的解决方案是。

import keyboard
from multiprocessing import Queue

q = Queue()
keyboard.add_hotkey("ctrl+alt+q", lambda: q.put("q"))
while q.empty():
    ...

解决方案 20:

import keyboard

while True:
    print('please say yes')
    if keyboard.is_pressed('y'):
         break
print('i got u :) ')
print('i was trying to write you are a idiot ')
print('  :( ')

使用 'ENTER' 输入

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用