Python 如何通过击键杀死while循环?

Python 如何通过击键杀死while循环?,python,while-loop,break,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) 所以。如何让用户跳出循环 另外,我不想使用键盘

我正在使用while循环读取串行数据并写入csv文件。我希望用户一旦觉得收集了足够的数据,就能够终止while循环

while True:
    #do a bunch of serial stuff

    #if the user presses the 'esc' or 'return' key:
        break
我使用opencv做过类似的事情,但它在这个应用程序中似乎不起作用(而且我真的不想只为这个函数导入opencv)

所以。如何让用户跳出循环


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

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

由于
Ctrl-C
会引发
键盘中断
,只需在循环外捕捉它并忽略它。

pyHook可能会有所帮助

参见键盘挂钩;如果您想要特定的键盘交互,而不仅仅是使用键盘中断,这是更普遍的

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


另请参见上一个问题:

有一种解决方案不需要非标准模块,并且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()

下面的代码适合我。它需要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 ...

始终存在
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()

对于Python3.7,我复制并更改了user297171提供的非常好的答案,因此它可以在我测试的Python3.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()
这可能会有帮助 使用安装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 

对于enter,使用“enter”

我修改了rayzinz的答案,以一个特定的键结束脚本,在本例中是escape键

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

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

循环一直持续,直到按下一个键
返回作为单个字符串按下的键

适用于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()

从兔子洞下面的这个线程,我来到了这个,在Win10和Ubuntu20.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()

下面是一个简单的Windows解决方案,它安全地结束当前迭代,然后退出。我用了一个反例,用“Esc”键打破循环并退出。它使用包中的函数。仅出于地役权原因调用时间包(设置事件之间的时间延迟)

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

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


b'\x1b'是“Esc”键的字节字符串字符。

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


@克丽丝:你为什么不试试呢。(然后评论)此崩溃(我得到错误跟踪)是
^C
是在
do\u something()
中发出的。如何避免这种情况?我的
do_something()
从USB读取一些值,因此,如果在我在
do_something()
内时发出
^C
,我会收到严重的通信错误。相反,如果我在
中,而
中,在
do_something()
之外,一切都很顺利。所以,我想知道如何处理这种情况。我不确定我说得是否足够清楚。@Atcold,所以您有一个正在使用的编译扩展模块。它是什么样的模块?这是一个正在包装的通用C库吗?我可以调用
pyVISA
matplotlib
,这样我就可以实时可视化我的测量结果。我有时会犯一些古怪的错误。我想我应该打开一个单独的问题,不要再污染你的答案了……请注意使用Python 3+的人:raw_input()已重命名为input(),线程模块现在是_thread。根据Python 3文档,在Python 3中不起作用:线程与中断进行奇怪的交互:键盘中断异常将由任意线程接收。(当信号模块可用时,中断总是转到主线程。)“@Towhid,但这不使用中断。它使用从stdin读取。@Artyer如果我没有弄错的话,所有的击键都会引发中断,因为它们是由硬件引发的。此代码对您有效吗?如果有效,您是否进行了任何特定更改?@Towhid只是
线程
->
\u线程
原始输入
->
输入
。您必须按enter键才能输入该行。如果你想在任何一把钥匙上使用。很好,但是cv2太重了,除非你已经在用它做其他的事情。为什么255@Talespin_Kit&0xff“屏蔽变量,使其仅保留最后8位中的值,并忽略所有其余位。基本上,它可以确保结果在0-255之间。注意,我从来没有在opencv中这样做过,一切都很好。我不知道我是否做错了什么,但我不知道如何停止这个循环?你是怎么做到的?@Mihkel你必须按这个键。这将导致循环退出。这很不错,但不能推广到除enter键以外的其他键。在python2.7上对我不起作用,但在Python3上起作用。在我的脑海中,多线程也是如此,但我非常喜欢上面@Keith的答案。简单明了,你好!虽然这段代码可以解决这个问题,但如何以及为什么解决这个问题将真正有助于提高
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()
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()
pip install keyboard

import keyboard

while True:
    # do something
    if keyboard.is_pressed("q"):
        print("q pressed, ending loop")
        break
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
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