如何用击键杀死while循环?

时间:2012-11-01 16:04:18

标签: python while-loop break

我正在读取串行数据并使用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循环终止后脚本需要继续运行。

15 个答案:

答案 0 :(得分:113)

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

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

由于Ctrl-C导致KeyboardInterrupt被引发,只需将其捕获到循环外部并忽略它。

答案 1 :(得分:27)

有一个解决方案不需要非标准模块,并且是100%可移动的

import thread

def input_thread(a_list):
    raw_input()
    a_list.append(True)

def do_stuff():
    a_list = []
    thread.start_new_thread(input_thread, (a_list,))
    while not a_list:
        stuff()

答案 2 :(得分:10)

以下代码适合我。它需要openCV(import cv2)。

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

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 ...

答案 3 :(得分:4)

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

看键盘挂钩;这更通用 - 如果你想要特定的键盘交互而不只是使用KeyboardInterrupt。

此外,一般情况下(取决于您的使用)我认为让Ctrl-C选项仍可用于终止您的脚本是有道理的。

另见上一个问题:Detect in python which keys are pressed

答案 4 :(得分:2)

对于Python 3.7,我复制并更改了user297171的非常好的答案,因此它可以在我测试的Python 3.7的所有情况下使用。

import _thread as thread

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

def do_stuff():
    thread.start_new_thread(key_capture_thread, ())
    while keep_going:
        print('still going...')

do_stuff()

答案 5 :(得分:2)

pip install keyboard

import keyboard

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

答案 6 :(得分:1)

我修改了rayzinnz的答案,以特定的键(在本例中为转义键)结束脚本

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()

答案 7 :(得分:1)

从这个问题开始,我来到了这一点,可以在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 \r\n
    print(string_to_print, end="\r\n")

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()

答案 8 :(得分:1)

这是一个对我有用的解决方案。从这里和其他地方的帖子中得到了一些想法。直到按下定义的键(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

答案 9 :(得分:0)

总有sys.exit()

Python核心库中的系统库具有退出功能,在进行原型制作时非常方便。 该代码将遵循以下原则:

import sys

while True:
    selection = raw_input("U: Create User\nQ: 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()

答案 10 :(得分:0)

这可能会有所帮助 用-安装pynput pip安装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 

答案 11 :(得分:0)

这是我在线程和标准库中找到的解决方案

循环一直进行到按下一个键为止
返回作为单个字符串按下的键

适用于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 :(得分:0)

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

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'\x1b' 是 'Esc' 键的字节串字符。

答案 13 :(得分:0)

这是另一个使用 threading.Event 的示例,无需捕获 SIGINT (Ctrl+c)。

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

在下面的示例中,用户需要先按 q,然后再按 Enter。如果您想立即捕获击键,则需要类似于 this answer 中的 _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()

答案 14 :(得分:-1)

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”