The 信号.警报 http://docs.python.org/library/signal.html?highlight=signal#signal.alarm不幸的是,@jer 推荐的解决方案所基于的函数仅适用于 Unix。如果您需要跨平台或特定于 Windows 的解决方案,您可以基于线程.定时器 http://docs.python.org/library/threading.html?#timer-objects相反,使用线程.interrupt_main http://docs.python.org/library/thread.html?highlight=interrupt_main#thread.interrupt_main发送一个KeyboardInterrupt
从定时器线程到主线程。 IE。:
import thread
import threading
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
timer = threading.Timer(timeout, thread.interrupt_main)
astring = None
try:
timer.start()
astring = input(prompt)
except KeyboardInterrupt:
pass
timer.cancel()
return astring
无论是 30 秒超时还是用户明确决定按 control-C 放弃输入任何内容,这都会返回 None,但以相同的方式处理这两种情况似乎可以(如果需要区分,可以使用对于计时器,您自己的函数,在中断主线程之前,在某处记录超时的事实has发生了,并且在你的处理程序中KeyboardInterrupt
访问该“某处”以区分发生了两种情况中的哪一种)。
Edit:我可以发誓这是有效的,但我一定是错的——上面的代码省略了明显需要的timer.start()
, and即使有了它,我也无法让它再工作了。select.select
显然,这是另一个值得尝试的事情,但它不适用于 Windows 中的“普通文件”(包括 stdin)——在 Unix 中,它适用于所有文件,而在 Windows 中,它仅适用于套接字。
所以我不知道如何进行跨平台“带超时的原始输入”。可以通过紧密循环轮询构建特定于 Windows 的轮询msvcrt.kbhit http://docs.python.org/library/msvcrt.html?highlight=msvcrt#msvcrt.kbhit,执行一个msvcrt.getche
(并检查是否返回以指示输出已完成,在这种情况下它会跳出循环,否则会累积并继续等待)并在需要时检查超时时间。我无法测试,因为我没有 Windows 机器(它们都是 Mac 和 Linux 的),但是这里未经测试的代码我会建议:
import msvcrt
import time
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
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
超时后,但是有什么选择呢?引发异常?返回不同的默认值?无论他想要什么选择,他都可以清楚地用它来代替我的return None
;-).
如果您不想仅仅因为用户正在输入而超时slowly(而不是根本不输入!-),您可以在每次成功输入字符后重新计算 finishat。