@jer推荐的解决方案所基于的signal.alarm函数不幸地是仅限于Unix。如果需要跨平台或特定于Windows的解决方案,可以基于threading.Timer而不是使用thread.interrupt_main从计时器线程向主线程发送KeyboardInterrupt。一、 e.:import thread
import threading
def raw_input_with_timeout(prompt, timeout=30.0):
print prompt,
timer = threading.Timer(timeout, thread.interrupt_main)
astring = None
try:
timer.start()
astring = raw_input(prompt)
except KeyboardInterrupt:
pass
timer.cancel()
return astring
无论是30秒超时还是用户显式地决定点击control-C放弃输入任何内容,这都不会返回任何结果,但是以同样的方式处理这两种情况似乎是可以的(如果需要区分,您可以为计时器使用自己的函数,在中断主线程之前,在某个地方记录以下事实超时已经发生,在您的处理程序中,KeyboardInterrupt访问该“某处”以区分发生了哪种情况)。
编辑:我本可以发誓这是有效的,但我肯定是错的——上面的代码忽略了明显需要的timer.start()、和即使使用它,我也无法使它继续工作。select.select这显然是另一种尝试,但它在Windows中不适用于“普通文件”(包括stdin)——在Unix中,它只适用于所有文件,在Windows中,仅适用于套接字。
所以我不知道如何做一个跨平台的“原始输入超时”。一个特定于windows的查询可以通过一个紧循环轮询msvcrt.kbhit来构造,执行一个msvcrt.getche(并检查它是否是一个返回以指示输出完成,在这种情况下,它会跳出循环,否则会累积并保持等待)并检查超时时间(如果需要)。我无法测试,因为我没有Windows机器(它们都是mac和Linux机器),但这里有未经测试的代码,我建议:import msvcrt
import time
def raw_input_with_timeout(prompt, timeout=30.0):
print prompt,
finishat = time.time() + timeout
result = []
while True:
if msvcrt.kbhit():
result.append(msvcrt.getche())
if result[-1] == '\r': # or \n, whatever Win returns;-)
return ''.join(result)
time.sleep(0.1) # just to yield to other processes/threads
else:
if time.time() > finishat:
return None
评论中的OP说他不想在超时时return None,但是有什么替代方法呢?提出一个例外?返回不同的默认值?无论他想要什么样的选择,他都可以很清楚地把它放在我的位置上。
如果您不想仅仅因为用户正在缓慢地键入而超时(与之相反,根本不键入!-),您可以在每次成功输入字符后重新计算finishat。