如何设置raw_input的时间限制

cal*_*pto 21 python timeout raw-input python-2.7

在python中,有没有办法在等待用户输入时计算时间,以便在30秒后raw_input()自动跳过该函数?

Ale*_*lli 28

不幸的是,@ jer建议的解决方案所基于的signal.alarm功能仅限于Unix.如果您需要跨平台或Windows特定的解决方案,则可以将其基于threading.Timer,使用thread.interrupt_mainKeyboardInterrupt从定时器线程向主线程发送.即:

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
Run Code Online (Sandbox Code Playgroud)

这将返回无,无论是30秒超时还是用户明确决定点击control-C放弃输入任何东西,但似乎可以用同样的方式处理这两种情况(如果你需要区分,你可以使用定时器自己的功能,中断主线程之前,记录某处的事实超时已经发生了,在你的处理器的KeyboardInterrupt访问是"地方"来区分这两个案件发生).

Edit: I could have sworn this was working but I must have been wrong -- the code above omits the obviously-needed timer.start(), and even with it I can't make it work any more. select.select would be the obvious other thing to try but it won't work on a "normal file" (including stdin) in Windows -- in Unix it works on all files, in Windows, only on sockets.

所以我不知道如何做一个跨平台的"带超时的原始输入".可以使用紧密循环轮询msvcrt.kbhit构造一个特定于Windows的窗口,执行a 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
Run Code Online (Sandbox Code Playgroud)

评论中的OP表示他不希望return None暂停,但是替代方案是什么?提出异常?返回不同的默认值?无论他想要什么样的替代品,他都可以清楚地代替我的return None;-).

如果你不想因为用户输入速度慢而超时(相反,根本不打字! - ),你可以在每次成功输入字符后重新计算.

  • @calccrypto,如果你想要一个与`None`不同的默认值,则将它作为参数添加到函数中; 我现在将它重新编码为仅限Windows(但由于我没有Windows而无法测试它)并完成它以便它将在30秒内终止,即使用户**正在慢慢打字(而不是等待) 30秒没有打字,这对我来说似乎是一个更明智的界面)虽然我也提到了如何轻松达到更理智的行为(你只需要在每个打字的字符成功读取后重置截止日期,所以只有30秒**不作为**将导致超时行为). (2认同)

jer*_*jer 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 ''
Run Code Online (Sandbox Code Playgroud)

请注意:此代码仅适用于*nix操作系统.