@ jer推荐的解决方案基于
signal.alarm功能,不幸的是仅限Unix.如果您需要跨平台或Windows特定的解决方案,则可以将其基于
threading.Timer,使用
thread.interrupt_main将KeyboardInterrupt从计时器线程发送到主线程.即:
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中,仅适用于套接字.
所以我不知道如何做一个跨平台的“带超时的原始输入”.可以使用紧密循环轮询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表示他不想在超时时返回None,但是替代方案是什么?提出异常?返回不同的默认值?无论他想要什么替代方案,他都可以清楚地代替我的回报无;-).
如果你不想因为用户输入速度慢而超时(相反,根本不打字! – ),你可以在每次成功输入字符后重新计算.