在Python中任意时间捕获用户输入
有没有办法在用户在控制台输入内容时,给一个Python模块发送一个中断信号?比如说,如果我在运行一个无限循环,我可以用try/except来包裹这个循环,这样当我按下键盘的中断键时,就可以在except块里处理我需要做的事情。
有没有办法用其他任意输入来实现类似的功能?比如说,某种控制序列或者标准字符?
补充说明:抱歉,这个是在Linux系统上。
6 个回答
KeyboardInterrupt 是一个特别的东西,它可以被捕捉到(在支持 POSIX 的操作系统中是 SIGINT,在 Windows 上是 SetConsoleCtrlHandler),然后进行相应的处理。如果你想在一个会阻塞的循环中处理用户输入,同时又想继续做其他事情,可以看看 threading
或 subprocess
这两个模块,了解一下如何在两个不同的线程或进程之间交换数据。同时,也要明白并行计算中会遇到的一些问题,比如竞争条件、线程安全和同步等。
你需要一个单独的进程(或者可能是一个线程)来读取终端的输入,然后通过某种方式把这些输入发送给你感兴趣的进程,这种方式叫做进程间通信(IPC)。如果是线程之间的通信可能会更复杂——基本上你能做的就是从一个辅助线程发送一个KeyboardInterrupt
到主线程。因为你说“我希望有一种简单的方法可以把用户输入注入到循环中,而不仅仅是按^C”,我很遗憾让你失望,但这就是事实:确实有方法可以做到你想要的,但这些方法并不简单。
根据操作系统和可用的库,有不同的方法可以实现这个功能。这个回答提供了几种方法。
这里是从那里复制的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对魔法值的不满,我也有同感。