在python的任意时间捕获用户input

有没有办法发送一个中断python模块时,用户在控制台中input的东西? 例如,如果我正在运行一个无限的while循环,我可以用一个try /除了KeyboardInterrupt来包围它,然后在except块中做我需要做的事情。

有没有办法用任何input复制这个function? 控制顺序还是标准字符?

编辑:对不起,这是在Linux上

取决于操作系统和可用的库,有不同的方式来实现这一点。 这个答案提供了其中的一些。

这里是从那里复制的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定义的curses.ascii ,感谢Daenyth对我分享的魔法值的不满。

你需要一个单独的进程(或可能是一个线程)来读取终端,并通过某种形式的进程间通信(IPC)将其发送到感兴趣的进程(线程间通信可能会更困难 – 基本上只有你做从辅助线程发送KeyboardInterrupt到主线程)。 既然你说“我希望有一个简单的方法来注入用户输入循环,而不仅仅是^ C”,我很伤心地让你失望,但是这是事实:有办法做你的要求,但简单的他们不是。

KeyboardInterrupt是特殊的,它可以被困住(即SIGINT在各自的POSIX支持,在Windows上的SetConsoleCtrlHandler操作系统),并相应地处理。 如果要在处理用户输入的同时在其他阻塞循环中进行工作,请查看threadingsubprocess进程模块,查看如何在两个不同的线程/进程之间交换数据。 另外请务必理解与并行计算(即竞态条件,线程安全/同步等)并行的问题。

我不知道这是否是最优化的解决方案,但你可以创建一个线程,一段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东西取决于你在哪里运行它。 它不会在任何地方工作。

这就是我如何实现我想要的功能,但这不完全是我的问题。 所以我会张贴这个,以防有人在寻找相同的概念,但接受一个更直接的答案。

 while True: try: time.sleep( 1 ) #do stuff except KeyboardInterrupt: inp = raw_input( '>' ) if inp == 'i': obj.integrate() elif inp == 'r': obj.reset() 

编辑:Guido在接受的答案上做了编辑,所以这个答案不再是必要的。

由于穆罕默德所做的改变,接受的答案不再有效。 我试图提交一个更正,但一直被拒绝,所以我会把它作为一个单独的答案。 我的代码和他的代码差不多,只有一个小小的变化:

 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)。我和另外一个开发者都测试了并确认这个改变是必须的,否则程序会不能正常工作。

该程序应该显示越来越大的数字,直到您按ESC,然后退出。 但是,如果没有ASCII()的ASCII码,它不会检测到你的ESC键。