如何给raw_input设置时间限制
在Python中,有没有办法在等待用户输入的同时,计时,比如说30秒后,自动跳过raw_input()
这个函数?
7 个回答
from threading import Timer
def input_with_timeout(x):
def time_up():
answer= None
print('time up...')
t = Timer(x,time_up) # x is amount of time in seconds
t.start()
try:
answer = input("enter answer : ")
except Exception:
print('pass\n')
answer = None
if answer != True: # it means if variable have somthing
t.cancel() # time_up will not execute(so, no skip)
input_with_timeout(5) # try this for five seconds
这个代码是自定义的... 在命令行里运行它,我希望你能得到答案。你可以看看这个 Python文档,这样你就能清楚地理解这个代码发生了什么!!
我在一篇博客文章中找到了这个问题的解决办法,链接在这里:博客文章。下面是那篇文章中的代码:
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
请注意:这段代码只适用于*nix操作系统。
signal.alarm 这个函数是@jer推荐的解决方案,但遗憾的是,它只能在Unix系统上使用。如果你需要一个可以在不同平台上都能用的解决方案,或者专门针对Windows的,可以考虑使用threading.Timer,并利用thread.interrupt_main从定时器线程向主线程发送一个KeyboardInterrupt
信号。也就是说:
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秒超时,还是用户主动按下控制键C放弃输入,这个方法都会返回None。不过,把这两种情况当作一样处理似乎没问题(如果你需要区分这两种情况,可以在定时器中使用你自己的函数,在打断主线程之前,记录下超时发生过的事实,然后在处理KeyboardInterrupt
时,查看这个“某个地方”,以判断是哪种情况发生了)。
编辑:我本以为这个方法是有效的,但我可能错了——上面的代码缺少了明显需要的timer.start()
,而且即使加上它,我也无法让它再工作了。select.select
是另一个显而易见的尝试,但在Windows上,它不能在“普通文件”(包括标准输入)上工作——在Unix上,它可以在所有文件上工作,而在Windows上,只能在套接字上工作。
所以我不知道怎么做一个跨平台的“带超时的原始输入”。可以用一个紧密的循环来轮询msvcrt.kbhit来构建一个Windows专用的方案,执行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
原问题的提问者在评论中说他不想在超时后return None
,但那有什么替代方案呢?抛出异常?返回一个不同的默认值?无论他想要什么替代方案,都可以直接替换掉我的return None
;-)。
如果你不想因为用户输入慢而超时(而不是根本不输入!),你可以在每次成功输入一个字符后重新计算结束时间。