How to kill a while loop with a keystroke?

我正在读取序列数据,并使用 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 循环结束后,脚本需要继续运行。

266559 次浏览

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

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

Since Ctrl-C causes KeyboardInterrupt to be raised, just catch it outside the loop and ignore it.

pyHook might help. http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial#tocpyHook%5FTutorial4

See keyboard hooks; this is more generalized-- if you want specific keyboard interactions and not just using KeyboardInterrupt.

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

另见前面的问题: 在 python 中检测哪些键被按下

There is a solution that requires no non-standard modules and is 100% transportable:

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

下面的代码适合我,它需要 openCV (import cv2)。

The code is composed of an infinite loop that is continuously looking for a key pressed. In this case, when the 'q' key is pressed, the program ends. Other keys can be pressed (in this example 'b' or 'k') to perform different actions such as change a variable value or execute a function.

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 核心库中的系统库有一个 exit 函数,在原型开发时非常方便。 代码大致如下:

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

For Python 3.7, I copied and changed the very nice answer by user297171 so it works in all scenarios in Python 3.7 that I tested.

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 安装输入输入法

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

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

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

循环继续进行,直到按下一个键
返回以单个字符串 < BR > < BR > 形式按下的键 用于 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和 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()
pip install keyboard


import keyboard


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

下面是一个简单的 Windows 解决方案,它可以安全地结束当前的迭代,然后退出。我使用它与一个反例,打破循环’Esc’键和退出。它使用 Msvcrt包中的 Kbhit ()抓住()函数。调用时间包只是为了缓解原因(设置事件之间的时间延迟)。

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() function returns True if a keypress is waiting to be read

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

B’x1b’ 是‘ Esc’键的字节串字符。

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

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

这里是另一个使用 threading.Event的例子,不需要捕获 SIGINT(Ctrl+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()
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")

这不是最好的方式,但它可以做你想要的工作 ,
运行 二线 one 等待要用来停止循环的键
(等待 _ Char 方法)
还有一个循环
(H 法)
两者都看到一个全局变量 停止 _ 标志控制停止过程 我按 z 的时候停止