如何给raw_input设置时间限制

24 投票
7 回答
45001 浏览
提问于 2025-04-15 23:18

在Python中,有没有办法在等待用户输入的同时,计时,比如说30秒后,自动跳过raw_input()这个函数?

7 个回答

4
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文档,这样你就能清楚地理解这个代码发生了什么!!

13

我在一篇博客文章中找到了这个问题的解决办法,链接在这里:博客文章。下面是那篇文章中的代码:

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操作系统

35

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;-)。

如果你不想因为用户输入而超时(而不是根本不输入!),你可以在每次成功输入一个字符后重新计算结束时间。

撰写回答