当用户在控制台中输入内容时,有没有办法向python模块发送中断?例如,如果我正在运行一个无限的while循环,我可以用try /除了KeyboardInterrupt来包围它,然后在except块中做我需要做的事情。
有没有办法用任意输入复制此功能?控制序列还是标准字符?
编辑:对不起,这是在linux上
答案 0 :(得分:2)
您需要一个单独的进程(或可能是一个线程)来读取终端并通过某种形式的进程间通信(IPC)将其发送到感兴趣的进程(线程间通信可能更难 - 基本上是唯一的你要做的是从一个辅助线程向主线程发送一个KeyboardInterrupt
。既然你说“我希望会有截获用户输入的不仅仅是^ C其他环路的简单方法”,我很伤心让你失望,但是这是事实:有方法可以做到你要求什么,但简单他们不是。
答案 1 :(得分:2)
取决于操作系统和可用的库,有不同的方法可以实现这一点。 This answer提供了其中一些内容。
这是从那里复制的Linux / OS X部分,使用转义字符终止无限循环。对于Windows解决方案,您可以检查答案本身。
import sys
import select
import tty
import termios
from curses import ascii
def isData():
return select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], [])
old_settings = termios.tcgetattr(sys.stdin)
try:
tty.setcbreak(sys.stdin.fileno())
i = 0
while 1:
print i
i += 1
if isData():
c = sys.stdin.read(1)
if c == chr(ascii.ESC):
break
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
修改:将字符检测更改为使用curses.ascii
定义的字符,这要归功于Daenyth对我所分享的魔法价值的不满。
答案 2 :(得分:1)
KeyboardInterrupt的特殊之处在于它可以被捕获(即在具有相应POSIX支持的操作系统下的SIGINT,Windows上的SetConsoleCtrlHandler)并相应地进行处理。如果你想在处理其他阻塞循环的同时处理用户输入,请查看threading
或subprocess
模块,看看如何在两个不同的线程之间交换数据/进程。还要确保了解与并行计算(即竞争条件,线程安全/同步等)相关的问题。
答案 3 :(得分:1)
我不确定它是否是最佳解决方案,但您可以创建一个执行while True: sys.stdin.read(1)
这样你就可以随时阅读所有输入,但它会很慢,你必须自己组合这些字符串。
示例:
import os
import sys
import time
import threading
class StdinReader(threading.Thread):
def run(self):
while True:
print repr(sys.stdin.read(1))
os.system('stty raw')
stdin_reader = StdinReader()
stdin_reader.start()
while True:
time.sleep(1)
os.system('stty sane')
stty raw
事情取决于你在哪里运行它。它无处不在。
答案 4 :(得分:0)
这就是我实现我想要的功能的方式,但我的问题并不完全正确。所以我会发布这个以防万一有人在寻找相同的概念,但接受一个更直接的答案。
while True:
try:
time.sleep( 1 )
#do stuff
except KeyboardInterrupt:
inp = raw_input( '>' )
if inp == 'i':
obj.integrate()
elif inp == 'r':
obj.reset()
答案 5 :(得分:0)
由于穆罕默德所做的改变,已接受的答案已不再有效。我试图提交更正,但它一直被拒绝,所以我会将其作为一个单独的答案发布。我的代码几乎与他的代码相同,只有一个很小的变化:
import sys
import select
import tty
import termios
from curses import ascii
def isData():
return select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], [])
old_settings = termios.tcgetattr(sys.stdin)
try:
tty.setcbreak(sys.stdin.fileno())
i = 0
while 1:
print i
i += 1
if isData():
c = sys.stdin.read(1)
if c == chr(ascii.ESC):
break
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
唯一的区别是“c == ascii.ESC”,而是将其更改为“c == chr(ascii.ESC)。我和其他1位开发人员都测试并确认此更改是必要的,否则该程序将无法正常工作。
程序应该显示越来越大的数字,直到你按ESC,然后退出。但是如果没有ascii.ESC周围的chr(),它就不会检测到你的ESC按键。