提问人:Chris 提问时间:11/2/2012 最后编辑:Chris 更新时间:8/23/2023 访问量:300690
如何通过击键杀死 while 循环?
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 循环终止后继续运行。
答:
最简单的方法是用通常的 (SIGINT) 打断它。Ctrl-C
try:
while True:
do_something()
except KeyboardInterrupt:
pass
既然要引起,就把它抓到循环之外,忽略它。Ctrl-C
KeyboardInterrupt
评论
^C
do_something()
do_something()
^C
do_something()
while
do_something()
pyVISA
matplotlib
pyHook 可能会有所帮助。http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial#tocpyHook%5FTutorial4
请参阅键盘挂钩;这更笼统 - 如果你想要特定的键盘交互,而不仅仅是使用 KeyboardInterrupt。
此外,一般来说(取决于您的使用情况),我认为仍然可以使用 Ctrl-C 选项来终止您的脚本是有意义的。
另请参阅上一个问题:在 python 中检测按下了哪些键
有一种解决方案不需要非标准模块,并且 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()
评论
thread
_thread
raw_input
input
以下代码对我有用。它需要 openCV(import 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()
评论
raw_input
input
对于 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()
评论
这可能会有所帮助 使用 -- 安装 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
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()
评论
这是我在线程和标准库
中找到的解决方案 循环一直持续下去,直到按下一个键 以单个字符串
的形式返回按下
的键 适用于 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() 和 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'\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
这是另一个使用线程的例子。事件
,无需捕获 ()。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")
这不是最好的方法,但它可以完成您想要的工作, 运行 2 个线程,
一个等待您想要停止
循环的键(Wait_Char 方法),一个用于循环
(H 方法),
并且都看到一个控制停止过程的全局变量stop_flag
按 z 时停止
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")
它有效......
接受的答案对我来说是不可靠的,但以下带有pyinput的解决方案有效(Python 3.10,Linux)。按下时,while循环结束:KeyboardInterrupt
q
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
您可以在 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")
如果您使用 Sleep 并且您有 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")
评论