【问题标题】:Time-Limited Input? [duplicate]限时输入? [复制]
【发布时间】:2013-03-09 20:46:37
【问题描述】:

我希望能够使用输入向用户提问。例如:

print('some scenario')
prompt = input("You have 10 seconds to choose the correct answer...\n")

然后如果时间过去了打印类似的东西

print('Sorry, times up.')

任何帮助我指出正确的方向将不胜感激。

【问题讨论】:

  • @interjay 在发布我的问题之前,我已经阅读了这篇文章。首先,我使用的是 Windows 平台而不是 Unix。接受的答案说它只是 Unix,我相信后来回答它的人说它甚至不起作用。我也在使用 Python 3。我需要使用输入而不是 raw_input。
  • 关于这个问题和 Francesco Frassinelli 发布的问题有多个答案,其中许多不是仅适用于 unix 的。您可以简单地将raw_input 更改为input。顺便说一句,当您提出问题时,您应该指定相关信息,例如在 Windows 上运行,以及您尝试过但没有奏效的解决方案,以免人们浪费时间重写旧答案。

标签: python input timer python-3.x python-multithreading


【解决方案1】:

如果在用户没有提供答案时阻塞主线程是可以接受的:

from threading import Timer

timeout = 10
t = Timer(timeout, print, ['Sorry, times up'])
t.start()
prompt = "You have %d seconds to choose the correct answer...\n" % timeout
answer = input(prompt)
t.cancel()

否则,您可以在 Windows(未测试)上使用 @Alex Martelli's answer(针对 Python 3 修改):

import msvcrt
import time

class TimeoutExpired(Exception):
    pass

def input_with_timeout(prompt, timeout, timer=time.monotonic):
    sys.stdout.write(prompt)
    sys.stdout.flush()
    endtime = timer() + timeout
    result = []
    while timer() < endtime:
        if msvcrt.kbhit():
            result.append(msvcrt.getwche()) #XXX can it block on multibyte characters?
            if result[-1] == '\r':
                return ''.join(result[:-1])
        time.sleep(0.04) # just to yield to other processes/threads
    raise TimeoutExpired

用法:

try:
    answer = input_with_timeout(prompt, 10)
except TimeoutExpired:
    print('Sorry, times up')
else:
    print('Got %r' % answer)

在 Unix 上你可以试试:

import select
import sys

def input_with_timeout(prompt, timeout):
    sys.stdout.write(prompt)
    sys.stdout.flush()
    ready, _, _ = select.select([sys.stdin], [],[], timeout)
    if ready:
        return sys.stdin.readline().rstrip('\n') # expect stdin to be line-buffered
    raise TimeoutExpired

或者:

import signal

def alarm_handler(signum, frame):
    raise TimeoutExpired

def input_with_timeout(prompt, timeout):
    # set signal handler
    signal.signal(signal.SIGALRM, alarm_handler)
    signal.alarm(timeout) # produce SIGALRM in `timeout` seconds

    try:
        return input(prompt)
    finally:
        signal.alarm(0) # cancel alarm

【讨论】:

  • 第一个答案在超时后确实打印了,但输入仍然可用。
  • @EliezerMiron: 是的,input() 调用在第一个示例中没有中断,这就是为什么有:"如果可以接受阻塞主线程" 之前这个例子。如果您需要中断输入,请使用以下示例和input_with_timeout()
  • 我尝试使用import signal ,它的时间感似乎很差。我正在使用 Cloud9 IDE。如果我给它一个 0.5 的超时时间,它会在超时前等待大约 3 秒。
  • 对于 windows 选项,您可能需要将 if result[-1] == '\n': 替换为 if result[-1] == '\r':(在 vscode、pwshell、cmd 和终端应用程序上测试过)
  • @DannyTalent 完成。
【解决方案2】:

有趣的问题,这似乎可行:

import time
from threading import Thread

answer = None

def check():
    time.sleep(2)
    if answer != None:
        return
    print("Too Slow")

Thread(target = check).start()

answer = input("Input something: ")

【讨论】:

  • 你可以use threading.Timer instead of Thread + time.sleep。 Python 3 中没有raw_input
  • raw_input() 如何在主线程中终止?我看到线程 check() 如何结束并将“太慢”推送到标准输出。但不是 raw_input() 如何填充或“完成”其标准输入缓冲区。
  • 这 (a) 不是 Python 3,并且 (b) 不起作用,原因是 @DevPlayer 指出的。
  • 为什么会被接受?
  • 这不应该被接受,它不会终止。
猜你喜欢
  • 2018-12-30
  • 1970-01-01
  • 2011-08-16
  • 1970-01-01
  • 2019-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-06
相关资源
最近更新 更多