键盘输入超时?

2024-11-26 08:36:00
admin
原创
143
摘要:问题描述:您将如何提示用户输入某些内容但在 N 秒后超时?Google 指向了有关该问题的邮件线程http://mail.python.org/pipermail/python-list/2006-January/533215.html,但似乎不起作用。发生超时的语句,无论是 asys.input.readl...

问题描述:

您将如何提示用户输入某些内容但在 N 秒后超时?

Google 指向了有关该问题的邮件线程http://mail.python.org/pipermail/python-list/2006-January/533215.html,但似乎不起作用。发生超时的语句,无论是 asys.input.readline还是timer.sleep(),我总是得到:

<type 'exceptions.TypeError'>: [raw_]input expected at most 1 arguments, got 2

不知何故,except 未能捕获。


解决方案 1:

使用 select 调用更短,并且更易于移植

import sys, select

print "You have ten seconds to answer!"

i, o, e = select.select( [sys.stdin], [], [], 10 )

if (i):
  print "You said", sys.stdin.readline().strip()
else:
  print "You said nothing!"

解决方案 2:

您链接的示例是错误的,异常实际上是在调用警报处理程序时发生的,而不是在读取块时发生的。最好试试这个:

import signal
TIMEOUT = 5 # number of seconds your want for timeout

def interrupted(signum, frame):
    "called when read times out"
    print 'interrupted!'
signal.signal(signal.SIGALRM, interrupted)

def input():
    try:
            print 'You have 5 seconds to type in your stuff...'
            foo = raw_input()
            return foo
    except:
            # timeout
            return

# set alarm
signal.alarm(TIMEOUT)
s = input()
# disable the alarm after success
signal.alarm(0)
print 'You typed', s

解决方案 3:

如果你不关心它是如何工作的,

pip install inputimeout

那么

from inputimeout import inputimeout, TimeoutOccurred

if __name__ == "__main__":
    try:
        c = inputimeout(prompt='hello
', timeout=3)
    except TimeoutOccurred:
        c = 'timeout'
    print(c)

非常简单

https://pypi.org/project/inputimeout/

解决方案 4:

这不是一个 Python 解决方案,但是......

我在 CentOS (Linux) 下运行脚本时遇到了这个问题,对我的情况有用的方法是在子进程中运行 Bash“read -t”命令。我知道这是一种残酷的令人厌恶的黑客行为,但我对它的效果感到很愧疚,所以我想在这里与大家分享。

import subprocess
subprocess.call('read -t 30', shell=True)

我所需要的只是等待 30 秒,除非按下 ENTER 键。这很有效。

解决方案 5:

这是一个在 Windows 上运行的

我无法让任何这些示例在 Windows 上运行,因此我合并了一些不同的 StackOverflow 答案以获得以下内容:


import threading, msvcrt
import sys

def readInput(caption, default, timeout = 5):
    class KeyboardThread(threading.Thread):
        def run(self):
            self.timedout = False
            self.input = ''
            while True:
                if msvcrt.kbhit():
                    chr = msvcrt.getche()
                    if ord(chr) == 13:
                        break
                    elif ord(chr) >= 32:
                        self.input += chr
                if len(self.input) == 0 and self.timedout:
                    break    


    sys.stdout.write('%s(%s):'%(caption, default));
    result = default
    it = KeyboardThread()
    it.start()
    it.join(timeout)
    it.timedout = True
    if len(it.input) > 0:
        # wait for rest of input
        it.join()
        result = it.input
    print ''  # needed to move to next line
    return result

# and some examples of usage
ans = readInput('Please type a name', 'john') 
print 'The name is %s' % ans
ans = readInput('Please enter a number', 10 ) 
print 'The number is %s' % ans 

解决方案 6:

Paul 的答案不太管用。下面修改后的代码对我有用

  • Windows 7 x64

  • 原始 CMD shell(例如,不是git-bash 或其他非 M$ shell)

——msvcrt看来 git-bash 中什么都不起作用。

  • 蟒蛇3.6

(我发布了一个新的答案,因为直接编辑 Paul 的答案会将其从 python 2.x-->3.x 更改,这对于编辑来说似乎太多了(py2 仍在使用中)

import sys, time, msvcrt

def readInput( caption, default, timeout = 5):

    start_time = time.time()
    sys.stdout.write('%s(%s):'%(caption, default))
    sys.stdout.flush()
    input = ''
    while True:
        if msvcrt.kbhit():
            byte_arr = msvcrt.getche()
            if ord(byte_arr) == 13: # enter_key
                break
            elif ord(byte_arr) >= 32: #space_char
                input += "".join(map(chr,byte_arr))
        if len(input) == 0 and (time.time() - start_time) > timeout:
            print("timing out, using default value.")
            break

    print('')  # needed to move to next line
    if len(input) > 0:
        return input
    else:
        return default

# and some examples of usage
ans = readInput('Please type a name', 'john') 
print( 'The name is %s' % ans)
ans = readInput('Please enter a number', 10 ) 
print( 'The number is %s' % ans) 

解决方案 7:

我花了大约二十分钟的时间,所以我认为值得一试,把它贴在这里。不过,它直接基于 user137673 的答案。我发现这样做最有用:

#! /usr/bin/env python

import signal

timeout = None

def main():
    inp = stdinWait("You have 5 seconds to type text and press <Enter>... ", "[no text]", 5, "Aw man! You ran out of time!!")
    if not timeout:
        print "You entered", inp
    else:
        print "You didn't enter anything because I'm on a tight schedule!"

def stdinWait(text, default, time, timeoutDisplay = None, **kwargs):
    signal.signal(signal.SIGALRM, interrupt)
    signal.alarm(time) # sets timeout
    global timeout
    try:
        inp = raw_input(text)
        signal.alarm(0)
        timeout = False
    except (KeyboardInterrupt):
        printInterrupt = kwargs.get("printInterrupt", True)
        if printInterrupt:
            print "Keyboard interrupt"
        timeout = True # Do this so you don't mistakenly get input when there is none
        inp = default
    except:
        timeout = True
        if not timeoutDisplay is None:
            print timeoutDisplay
        signal.alarm(0)
        inp = default
    return inp

def interrupt(signum, frame):
    raise Exception("")

if __name__ == "__main__":
    main()

解决方案 8:

以下代码对我有用。

我使用了两个线程,一个用于获取 raw_Input,另一个用于等待特定时间。如果任何一个线程退出,则两个线程都会终止并返回。

def _input(msg, q):
    ra = raw_input(msg)
    if ra:
        q.put(ra)
    else:
        q.put("None")
    return

def _slp(tm, q):
    time.sleep(tm)
    q.put("Timeout")
    return

def wait_for_input(msg="Press Enter to continue", time=10):
    q = Queue.Queue()
    th = threading.Thread(target=_input, args=(msg, q,))
    tt = threading.Thread(target=_slp, args=(time, q,))

    th.start()
    tt.start()
    ret = None
    while True:
        ret = q.get()
        if ret:
            th._Thread__stop()
            tt._Thread__stop()
            return ret
    return ret

print time.ctime()    
t= wait_for_input()
print "
Response :",t 
print time.ctime()

解决方案 9:

这是一个使用线程的可移植且简单的 Python 3 解决方案。这是唯一一个对我有用的跨平台解决方案。

我尝试过的其他方法都遇到了问题:

  • 使用 signal.SIGALRM:在 Windows 上不起作用

  • 使用选择调用:在 Windows 上不起作用

  • 强制终止进程(而不是线程):stdin 不能在新进程中使用(stdin 会自动关闭)

  • 将 stdin 重定向到 StringIO 并直接写入 stdin:如果已经调用 input() ,则仍将写入先前的 stdin (请参阅https://stackoverflow.com/a/15055639/9624704

    from threading import Thread
    class myClass:
        _input = None

        def __init__(self):
            get_input_thread = Thread(target=self.get_input)
            get_input_thread.daemon = True  # Otherwise the thread won't be terminated when the main program terminates.
            get_input_thread.start()
            get_input_thread.join(timeout=20)

            if myClass._input is None:
                print("No input was given within 20 seconds")
            else:
                print("Input given was: {}".format(myClass._input))


        @classmethod
        def get_input(cls):
            cls._input = input("")
            return

解决方案 10:

对于 Linux,我更喜欢select@Pontus 的版本。这里只有一个 python3 函数,就像在 shell 中一样read

import sys, select

def timeout_input(prompt, timeout=3, default=""):
    print(prompt, end=': ', flush=True)
    inputs, outputs, errors = select.select([sys.stdin], [], [], timeout)
    print()
    return (0, sys.stdin.readline().strip()) if inputs else (-1, default)

跑步

In [29]: timeout_input("Continue? (Y/n)", 3, "y")                                                                                                                                                                  
Continue? (Y/n): 
Out[29]: (-1, 'y')

In [30]: timeout_input("Continue? (Y/n)", 3, "y")                                                                                                                                                                  
Continue? (Y/n): n

Out[30]: (0, 'n')

以及一个yes_or_no函数

In [33]: yes_or_no_3 = lambda prompt: 'n' not in timeout_input(prompt + "? (Y/n)", 3, default="y")[1].lower()                                                                                                      

In [34]: yes_or_no_3("Continue")                                                                                                                                                                                   
Continue? (Y/n): 
Out[34]: True

In [35]: yes_or_no_3("Continue")                                                                                                                                                                                   
Continue? (Y/n): no

Out[35]: False

解决方案 11:

我的跨平台解决方案

def input_process(stdin_fd, sq, str):
    sys.stdin = os.fdopen(stdin_fd)
    try:
        inp = input (str)
        sq.put (True)
    except:
        sq.put (False)

def input_in_time (str, max_time_sec):
    sq = multiprocessing.Queue()
    p = multiprocessing.Process(target=input_process, args=( sys.stdin.fileno(), sq, str))
    p.start()
    t = time.time()
    inp = False
    while True:
        if not sq.empty():
            inp = sq.get()
            break
        if time.time() - t > max_time_sec:
            break
    p.terminate()
    sys.stdin = os.fdopen( sys.stdin.fileno() )
    return inp

解决方案 12:

from threading import Thread
import time


def get_input():
    while True:
        print(input('> '))


t1 = Thread(target=get_input)
t1.setDaemon(True)
t1.start()
time.sleep(3)
print('program exceeds')

好吧,只需设置一个新的守护线程,并设置一个睡眠时间,无论你想要超时多少时间。我认为这很容易赶上 XD

解决方案 13:

已经过去好几年了,但万一有人像我最近尝试解决此类问题时遇到这种情况,有一个更简单、更快捷的方法可以使用func-timeout包来实现。大多数 IDE 在使用前必须安装它;您可以通过 进行安装pip。上面的链接是不言自明的,但我将给出一个如何实现它的示例。

from func_timeout import FunctionTimedOut, func_timeout

try:
   ans = func_timeout(5, lambda: int(input('What is the sum of 2 and 3?
')))
   print(ans)
except FunctionTimedOut:
   print(5)

func_timeout返回方法的值作为其参数,question()在本例中为函数。它还允许函数所需的其他参数(请参阅文档)。如果设置的时间过去(此处为 5 秒),它会引发TimedOutException并运行块中的代码except

解决方案 14:

类似于 Locane 的窗口:

import subprocess  
subprocess.call('timeout /T 30')

解决方案 15:

修改后的 iperov 答案对我有用(python3 win10 2019-12-09)

iperov 的变更:

  • 用 sstr 替换 str,因为 str 是 python 中的一个函数

  • 添加导入

  • 添加睡眠以降低 while 循环的 CPU 使用率(?)

  • 添加 if name ==' main ': #windows 上的多处理需要

导入系统、操作系统、多处理、时间

def input_process(stdin_fd, sq, sstr):
    sys.stdin = os.fdopen(stdin_fd)
    try:
        inp = input(sstr)
        sq.put(True)
    except:
        sq.put(False)

def input_in_time(sstr, max_time_sec):
    sq = multiprocessing.Queue()
    p = multiprocessing.Process(target=input_process, args=( sys.stdin.fileno(), sq, sstr))
    p.start()
    t = time.time()
    inp = False
    while True:

        if not sq.empty():
            inp = sq.get()
            break
        if time.time() - t > max_time_sec:
            break

        tleft=int( (t+max_time_sec)-time.time())
        if tleft<max_time_sec-1 and tleft>0:
            print('
  ...time left '+str(tleft)+'s
command:')

        time.sleep(2)

    p.terminate()
    sys.stdin = os.fdopen( sys.stdin.fileno() )
    return inp

if __name__=='__main__':
    input_in_time("command:", 17)

解决方案 16:

您可以在 Python >= 3.4 中使用inputimeout lib。MIT 许可证。

$ pip install inputimeout

from inputimeout import inputimeout, TimeoutOccurred
try:
    something = inputimeout(prompt='>>', timeout=5)
except TimeoutOccurred:
    something = 'something'
print(something)

解决方案 17:

这是我解决这个问题的方法。我还没有彻底测试过,也不确定它是否存在一些重要的问题,但考虑到其他解决方案也远非完美,我决定分享一下:

import sys
import subprocess


def switch():
    if len(sys.argv) == 1:
        main()
    elif sys.argv[1] == "inp":
        print(input(''))
    else:
        print("Wrong arguments:", sys.argv[1:])


def main():
    passw = input_timed('You have 10 seconds to enter password:', timeout=10)
    if passw is None:
        print("Time's out! You explode!")
    elif passw == "PasswordShmashword":
        print("H-h-how did you know you h-h-hacker")
    else:
        print("I spare your life because you at least tried")


def input_timed(*args, timeout, **kwargs):
    """
    Print a message and await user input - return None if timedout
    :param args: positional arguments passed to print()
    :param timeout: number of seconds to wait before returning None
    :param kwargs: keyword arguments passed to print()
    :return: user input or None if timed out
    """
    print(*args, **kwargs)
    try:
        out: bytes = subprocess.run(["python", sys.argv[0], "inp"], capture_output=True, timeout=timeout).stdout
    except subprocess.TimeoutExpired:
        return None
    return out.decode('utf8').splitlines()[0]


switch()

解决方案 18:

import datetime, time

def custom_time_input(msg, seconds):
    try:
        print(msg)
        # current time in seconds
        current_time = datetime.datetime.now()
        time_after = current_time + datetime.timedelta(seconds=seconds)
        while datetime.datetime.now() < time_after:
            print("Time left: ", end="")
            print(time_after - datetime.datetime.now(), end="
")
            time.sleep(1)
        print("
")
        return True
    except KeyboardInterrupt:
        return False

res = custom_time_input("If you want to create a new config file PRESS CTRL+C within 20 seconds!", 20)
if res:
    pass # nothing changed
else:
    pass # do something because user pressed ctrl+c

解决方案 19:

解决方案受到 iperov 的答案的启发,希望它更清晰一些:

import multiprocessing
import sys

def input_with_timeout(prompt, timeout=None):
    """Requests the user to enter a code at the command line."""
    queue = multiprocessing.Queue()
    process = multiprocessing.Process(
        _input_with_timeout_process, args=(sys.stdin.fileno(), queue, prompt),
    )
    process.start()
    try:
        process.join(timeout)
        if process.is_alive():
            raise ValueError("Timed out waiting for input.")
        return queue.get()
    finally:
        process.terminate()


def _input_with_timeout_process(stdin_file_descriptor, queue, prompt):
    sys.stdin = os.fdopen(stdin_file_descriptor)
    queue.put(input(prompt))

解决方案 20:

这是一种 Python 3.8+(尽管它可以适应 Python 3.6+)跨平台方法,仅使用threading(因此不multiprocessing调用 shell 实用程序)。它旨在从命令行运行脚本,不太适合动态使用。

您可以按如下方式包装内置input函数。 在这种情况下,我将内置名称重新定义input为包装器,因为此实现要求所有调用都input通过此路由。 (免责声明:这就是为什么它可能不是一个很好的主意,只是为了好玩而提出的一个不同的想法。)

import atexit
import builtins
import queue
import threading


def _make_input_func():
    prompt_queue = queue.Queue(maxsize=1)
    input_queue = queue.Queue(maxsize=1)

    def get_input():
        while (prompt := prompt_queue.get()) != GeneratorExit:
            inp = builtins.input(prompt)
            input_queue.put(inp)
            prompt_queue.task_done()

    input_thread = threading.Thread(target=get_input, daemon=True)

    last_call_timed_out = False

    def input_func(prompt=None, timeout=None):
        """Mimics :function:`builtins.input`, with an optional timeout

        :param prompt: string to pass to builtins.input
        :param timeout: how long to wait for input in seconds; None means indefinitely

        :return: the received input if not timed out, otherwise None
        """
        nonlocal last_call_timed_out

        if not last_call_timed_out:
            prompt_queue.put(prompt, block=False)
        else:
            print(prompt, end='', flush=True)

        try:
            result = input_queue.get(timeout=timeout)
            last_call_timed_out = False
            return result
        except queue.Empty:
            print(flush=True) # optional: end prompt line if no input received
            last_call_timed_out = True
            return None


    input_thread.start()
    return input_func


input = _make_input_func()
del _make_input_func

(我已经在一次性使用中定义了设置,_make_input_func以在其闭包中隐藏input“静态”变量,以避免污染全局命名空间。)

这里的想法是创建一个单独的线程来处理对 的所有调用builtins.input,并让input包装器管理超时。由于对 的调用builtins.input始终阻塞直到有输入,因此当超时结束时,特殊线程仍在等待输入,但input包装器返回(带有None)。在下一次调用时,如果上次调用超时,则不需要builtins.input再次调用(因为输入线程已经在等待输入),它只需打印提示,然后像往常一样等待所述线程返回一些输入。

定义完上述内容后,尝试运行以下脚本:

import time

if __name__ == '__main__':
    timeout = 2
    start_t = time.monotonic()
    if (inp := input(f"Enter something (you have {timeout} seconds): ", timeout)) is not None:
        print("Received some input:", repr(inp))
    else:
        end_t = time.monotonic()
        print(f"Timed out after {end_t - start_t} seconds")

    inp = input("Enter something else (I'll wait this time): ")
    print("Received some input:", repr(inp))
    
    input(f"Last chance to say something (you have {timeout} seconds): ", timeout)

解决方案 21:

有些答案要求Enter在超时时按下该键才能继续运行代码。其他答案似乎很复杂,而且Enter在超时后仍然需要按下该键。

我在另一个线程中找到了答案,它工作得很好,但我发现了一个警告。为了便于移植,我决定将我的代码放在一个class

笔记

我必须使用keyboard来注入Enter按键,因为input()我的代码中还有另一个语句。出于某种原因,input()除非我按下按键,否则后续语句不会出现Enter

import threading
import keyboard    # https://github.com/boppreh/keyboard

class Utilities:

    # Class variable
    response = None

    @classmethod
    def user_input(cls, timeout):

        def question():
            cls.response = input("Enter something: ")

        t = threading.Thread(target=question)
        # Daemon property allows the target function to terminate after timeout
        t.daemon = True    
        t.start()
        t.join(timeout)

        if cls.response:
            # Do something
        else:
            # Do something else
            # Optional.  Use if you have other input() statements in your code
            keyboard.send("enter")

用法

Utilities.user_input(3)

这是使用 Windows 10 上的 Python 3.8.3 制作的。

解决方案 22:

这是 Linux 上 Python 3.8+ 的另一个版本,其中包含一个 yes_no 答案,默认超时返回

import signal
def alarm_handler(signum, frame):
    raise TimeoutError
def input_with_timeout(prompt, timeout=30):
    """ get input with timeout

    :param prompt: the prompt to print
    :param timeout: timeout in seconds, or None to disable

    :returns: the input
    :raises: TimeoutError if times out
    """
    # set signal handler
    if timeout is not None:
        signal.signal(signal.SIGALRM, alarm_handler)
        signal.alarm(timeout) # produce SIGALRM in `timeout` seconds
    try:
        return input(prompt)
    except TimeoutError as to:
        raise to
    finally:
        if timeout is not None:
            signal.alarm(0) # cancel alarm

def yes_or_no(question, default='y', timeout=None):
    """ Get y/n answer with default choice and optional timeout

    :param question: prompt
    :param default: the default choice, i.e. 'y' or 'n'
    :param timeout: the timeout in seconds, default is None

    :returns: True or False
    """
    if default is not None and (default!='y' and default!='n'):
        log.error(f'bad option for default: {default}')
        quit(1)
    y='Y' if default=='y' else 'y'
    n='N' if default=='n' else 'n'
    while "the answer is invalid":
        try:
            to_str='' if timeout is None else f'(Timeout {default} in {timeout}s)'
            reply = str(input_with_timeout(f'{question} {to_str} ({y}/{n}): ',timeout=timeout)).lower().strip()
        except TimeoutError:
            log.warning(f'timeout expired, returning default={default} answer')
            reply=''
        if len(reply)==0:
            return True if default=='y' else False
        elif reply[0] == 'y':
            return True
        if reply[0] == 'n':
            return False

代码使用示例


if yes_or_no(f'model {latest_model_folder} exists, start from it?', timeout=TIMEOUT):
     log.info(f'initializing model from {latest_model_folder}')
     model = load_model(latest_model_folder)
else:
     log.info('creating new empty model')
     model = create_model()

解决方案 23:

我正在使用外部工具inputimeout。源代码可在github上找到。我知道这是一个外部工具,但它很简单而且非常方便。安装该工具后,使用此代码:

from inputimeout import inputimeout, TimeoutOccurred
try:
    something = inputimeout(prompt='>>', timeout=5)
except TimeoutOccurred:
    something = 'No input.'
print(something)

解决方案 24:

扩展上一个使用inputtimeout的答案,并给出一个简单的例子

from inputimeout import inputimeout, TimeoutOccurred

def timed_input (user_prompt, timeout=5):
    user_input = ""
    timed_out = False
    try:
        user_input = inputimeout (prompt=user_prompt, timeout=timeout)
    except TimeoutOccurred:
        timed_out = True
    return (timed_out, user_input)

timed_out, user_input = timed_input ("Enter something within 3s... ", timeout=3)

if timed_out:
    print ("You failed to enter anything!")
else:
    print (f"You entered {user_input}")

解决方案 25:

这是我写的代码。使用多处理,我们可以使输入超时。

from multiprocessing import Queue, Process
from queue import Empty

class ProcessTimedOutException(Exception):
    def __init__(self, message: str):
        self.message: str = message


class Terminal:

    @staticmethod
    def input_with_timeout(message: str = '', timeout: int = 60) -> Tuple[Optional[str], Optional[Exception]]:
        queue = Queue()
        err: Optional[Exception] = None
        user_input: Optional[str] = None
        input_thread = Process(target=Terminal._input_async, args=(queue, message), daemon=True)
        input_thread.start()
        try:
            user_input = queue.get(timeout=timeout)
        except Empty:
            input_thread.terminate()
            err = ProcessTimedOutException(f'process timed out')
        return user_input, err

    @staticmethod
    def _input_async(queue, message: str = ''):
        sys.stdin = open(0)
        user_input = input(message).strip()
        queue.put(user_input)


if __name__ == '__main__':
    input_message: str = 'enter anything'
    user_input, err = Terminal.input_with_timeout(message=input_message,timeout=60)
    if err is not None:
        raise err
    print(user_input)                    

解决方案 26:

我遇到了同样的问题,并使用键盘和 kthread 解决了它。只要按下回车键,输入字段就会消失。这对我来说是最重要的事情,但我无法通过其他方法使其工作。

如果需要,你可以使用 pip 安装它:

pip install input-timeout

以下是一些示例:

        from input_timeout import InputTimeout



        i = InputTimeout(

            timeout=20,

            input_message=" >> ",

            timeout_message="'Sorry, you were not fast enough'",

            defaultvalue="slow",

            cancelbutton="esc",

            show_special_characters_warning='If you want to use special characters, you have to use alt+\\d\\d\\d\\d
Press "ctrl" to see a complete list of all combinations!',

        ).finalvalue

        print(f"

Your input was {i}")



        i = InputTimeout(

            timeout=5,

            input_message=" >> ",

            timeout_message="Sorry, you were not fast enough: ",

            defaultvalue="slow",

            cancelbutton="esc",

            show_special_characters_warning='If you want to use special characters, you have to use alt+\\d\\d\\d\\d
Press "ctrl" to see a complete list of all combinations!',

        ).finalvalue

        print(f"

Your input was {i}")



        i = InputTimeout(

            timeout=10,

            input_message=" >> ",

            timeout_message="Sorry, you were not fast enough",

            defaultvalue="Wake up!",

            cancelbutton=None,

            show_special_characters_warning=None,

        ).finalvalue

        print(f"

Your input was {i}")



        i = InputTimeout(

            timeout=10,

            input_message=" >> ",

            timeout_message="Sorry, you were not fast enough",

            defaultvalue="Are you sleeping?",

            cancelbutton="esc",

            show_special_characters_warning=None,

        ).finalvalue

        print(f"

Your input was {i}")



        i = InputTimeout(

            timeout=10,

            input_message=" >>",

            timeout_message="Sorry, you were not fast enough",

            defaultvalue="you are so slow",

            cancelbutton=None,

            show_special_characters_warning='If you want to use special characters, you have to use alt+\\d\\d\\d\\d
Press "ctrl" to see a complete list of all combinations!',

        ).finalvalue

        print(f"

Your input was {i}")

#output

If you want to use special characters, you have to use alt+dddd

Press "ctrl" to see a complete list of all combinations!

 >>  babba

Your input was babba

If you want to use special characters, you have to use alt+dddd

Press "ctrl" to see a complete list of all combinations!

alt+0192    ->  À       alt+0193    ->  Á       alt+0196    ->  Ä       alt+0194    ->  Â       

alt+0195    ->  Ã       alt+0197    ->  Å       alt+0198    ->  Æ       alt+0228    ->  ä       

alt+0224    ->  à       alt+0225    ->  á       alt+0226    ->  â       alt+0227    ->  ã       

alt+0229    ->  å       alt+0230    ->  æ       alt+0199    ->  Ç       alt+0231    ->  ç       

alt+0208    ->  Ð       alt+0240    ->  ð       alt+0203    ->  Ë       alt+0200    ->  È       

alt+0201    ->  É       alt+0202    ->  Ê       alt+0235    ->  ë       alt+0232    ->  è       

alt+0233    ->  é       alt+0234    ->  ê       alt+0207    ->  Ï       alt+0204    ->  Ì       

alt+0205    ->  Í       alt+0206    ->  Î       alt+0239    ->  ï       alt+0236    ->  ì       

alt+0237    ->  í       alt+0238    ->  î       alt+0209    ->  Ñ       alt+0241    ->  ñ       

alt+0214    ->  Ö       alt+0210    ->  Ò       alt+0211    ->  Ó       alt+0212    ->  Ô       

alt+0213    ->  Õ       alt+0216    ->  Ø       alt+0140    ->  Œ       alt+0246    ->  ö       

alt+0242    ->  ò       alt+0243    ->  ó       alt+0244    ->  ô       alt+0245    ->  õ       

alt+0248    ->  ø       alt+0156    ->  œ       alt+0138    ->  Š       alt+0223    ->  ß       

alt+0154    ->  š       alt+0222    ->  Þ       alt+0254    ->  þ       alt+0220    ->  Ü       

alt+0217    ->  Ù       alt+0218    ->  Ú       alt+0219    ->  Û       alt+0252    ->  ü       

alt+0249    ->  ù       alt+0250    ->  ú       alt+0251    ->  û       alt+0159    ->  Ÿ       

alt+0221    ->  Ý       alt+0255    ->  ÿ       alt+0253    ->  ý       alt+0168    ->  ¨       

alt+0136    ->  ˆ       alt+0180    ->  ´       alt+0175    ->  ¯       alt+0184    ->  ¸       

alt+0192    ->  À       alt+0193    ->  Á       alt+0196    ->  Ä       alt+0194    ->  Â       

alt+0195    ->  Ã       alt+0197    ->  Å       alt+0198    ->  Æ       alt+0228    ->  ä       

alt+0224    ->  à       alt+0225    ->  á       alt+0226    ->  â       alt+0227    ->  ã       

alt+0229    ->  å       alt+0230    ->  æ       alt+0199    ->  Ç       alt+0231    ->  ç       

alt+0208    ->  Ð       alt+0240    ->  ð       alt+0203    ->  Ë       alt+0200    ->  È       

alt+0201    ->  É       alt+0202    ->  Ê       alt+0235    ->  ë       alt+0232    ->  è       

alt+0233    ->  é       alt+0234    ->  ê       alt+0207    ->  Ï       alt+0204    ->  Ì       

alt+0205    ->  Í       alt+0206    ->  Î       alt+0239    ->  ï       alt+0236    ->  ì       

alt+0237    ->  í       alt+0238    ->  î       alt+0209    ->  Ñ       alt+0241    ->  ñ       

alt+0214    ->  Ö       alt+0210    ->  Ò       alt+0211    ->  Ó       alt+0212    ->  Ô       

alt+0213    ->  Õ       alt+0216    ->  Ø       alt+0140    ->  Œ       alt+0246    ->  ö       

alt+0242    ->  ò       alt+0243    ->  ó       alt+0244    ->  ô       alt+0245    ->  õ       

alt+0248    ->  ø       alt+0156    ->  œ       alt+0138    ->  Š       alt+0223    ->  ß       

alt+0154    ->  š       alt+0222    ->  Þ       alt+0254    ->  þ       alt+0220    ->  Ü       

alt+0217    ->  Ù       alt+0218    ->  Ú       alt+0219    ->  Û       alt+0252    ->  ü       

alt+0249    ->  ù       alt+0250    ->  ú       alt+0251    ->  û       alt+0159    ->  Ÿ       

alt+0221    ->  Ý       alt+0255    ->  ÿ       alt+0253    ->  ý       alt+0168    ->  ¨       

alt+0136    ->  ˆ       alt+0180    ->  ´       alt+0175    ->  ¯       alt+0184    ->  ¸       

Sorry, you were not fast enough: 

Your input was slow

 >>  super

Your input was super

 >>  adasa

Your input was adasa

If you want to use special characters, you have to use alt+dddd

Press "ctrl" to see a complete list of all combinations!

Sorry, you were not fast enough

Your input was you are so slow

解决方案 27:

2022 年 11 月, pypi 存储库中有一个名为的 Python 3 项目,由werecatfpytimedinput编写。它在我的 Windows 10 系统上运行良好。您可以pip像这样安装它:

C:UsersUser> pip install pytimedinput

以下是一个使用示例:

from pytimedinput import timedInput
userText, timedOut = timedInput("Enter something: ", timeout=5)
if(timedOut):
    print("Timed out when waiting for input.")
    print(f"User-input so far: '{userText}'")
else:
    print(f"User-input: '{userText}'")

解决方案 28:

可以使用 asyncio 来实现这一点。本质上结合https://stackoverflow.com/a/65909044/3005167https://stackoverflow.com/a/54787498/3005167会导致如下结果:

import asyncio
import sys


async def main():
    reader = asyncio.StreamReader()
    pipe = sys.stdin
    loop = asyncio.get_event_loop()
    await loop.connect_read_pipe(lambda: asyncio.StreamReaderProtocol(reader), pipe)

    got_input = None

    async def get_input():
        nonlocal got_input
        inp = await anext(aiter(reader))
        got_input = inp.decode()

    tasks = [asyncio.create_task(asyncio.sleep(5)), asyncio.create_task(get_input())]

    await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)

    if got_input is None:
        print("Time up!")
    else:
        print("Input: ", got_input)


if __name__ == "__main__":
    asyncio.run(main())

解决方案 29:

我将重点介绍 Windows 解决方案,因为 Unix 解决方案已在此线程中多次提出(使用 API select)。

一些解决方案建议使用该msvcrt.kbhit()函数来检查是否有用户输入。仅当程序在交互式控制台中运行时,该函数才有效,并且它不处理使用基于管道的通信的多处理情况。我的解决方案依赖于直接使用pywin32库的 Windows API:

import msvcrt
import time
import win32api, win32file, win32pipe


def input_timeout(timeout: float) -> str:
    """
    Waits for specified period in seconds for user input. If user input is not received in time
    function raises exception.
    """
    start = time.time()
    handle = win32api.GetStdHandle(win32api.STD_INPUT_HANDLE)
    typ = win32file.GetFileType(handle)
    buffer = ""
    while (time.time() - start) < timeout:
        # check the type of stdin handle
        if typ == win32file.FILE_TYPE_PIPE:
            # limited to 1024 bytes per line !!!
            data, _, _ = win32pipe.PeekNamedPipe(handle, 1024)
            # usage of CR or LF depends on what data you send to subprocess
            if "
" in data:
                return input()
            else:
                time.sleep(0.1)
        else:
            while msvcrt.kbhit():
                ch = msvcrt.getwche()
                if ch == "x08":
                    buffer = buffer[:-1]
                # windows interactive console uses CR character (consider handling 
 too)
                elif ch == "
":
                    print()  # add missing LF
                    return buffer
                # possibly other control characters need to be handled here
                else:
                    buffer += ch
            time.sleep(0.1)
    
    print("Buffer:", repr(buffer))
    raise TimeoutError()


# prompt
print("Enter value (you only have 2.5 seconds): ", end="", flush=True)
val = input_timeout(2.5)
print("Value entered:", val)

我个人建议使用专用线程通过回调来处理 stdin 输入。很多人尝试使用守护进程线程来处理 stdin,并且他们依赖系统在应用程序退出时终止线程,这显然是一种不好的做法 - 你总是需要清理你的烂摊子。这是我的解决方案:

import threading
import time
from typing import Callable, Optional
import win32api, win32event, win32file, win32pipe


def hook_input(callback: Callable[[str], None], keep_running: threading.Event) -> threading.Thread:
    """
    Creates background thread that waits for input on stdin. When a new line is read from stdin
    the callback is called with line read from stdin. You can use keep_running flag to terminate
    background thread gracefully.
    """
    def thread_fun(cb: Callable[[str], None], flag: threading.Event):
        handle = win32api.GetStdHandle(win32api.STD_INPUT_HANDLE)
        typ = win32file.GetFileType(handle)
        while keep_running.is_set():
            # WaitForSingleObject is not supported when stdin is pipe (e.g. when running as subprocess)
            if typ == win32file.FILE_TYPE_PIPE:
                # alternatively you can specify nonzero parameter to retrieve data in pipe buffer
                # and check for LF character before calling input() function
                _, available, _ = win32pipe.PeekNamedPipe(handle, 0)
                if available > 0:
                    cb(input())
                else:
                    time.sleep(0.1)
            else:
                # alternatively you cn use msvcrt.kbhit() with msvcrt.getwche() function, but you
                # neet to handle control characters yourself (such as 0x08)
                if win32event.WaitForSingleObject(handle, 100) == win32event.WAIT_OBJECT_0:
                    cb(input())
                else:
                    time.sleep(0.1)
    
    thread = threading.Thread(target=thread_fun, args=(callback, keep_running), daemon=False)
    thread.start()
    return thread


# hook input
flag = threading.Event()
flag.set()
thr = hook_input(lambda val: print("Received:", val), flag)

# do your stuff

# finish
flag.clear()
thr.join()

您还可以在回调函数中处理用户输入超时。asyncio如果您将time.sleep()函数替换为,则第二种实现可以安全地与库一起使用asyncio.sleep()。请注意,在这种情况下将阻止事件循环运行,因此我建议您将短函数与长函数WaitForSingleObject()结合使用。WaitForSingleObject()`asyncio.sleep()`

解决方案 30:

回答晚了:)

我会做这样的事情:

from time import sleep

print('Please provide input in 20 seconds! (Hit Ctrl-C to start)')
try:
    for i in range(0,20):
        sleep(1) # could use a backward counter to be preeety :)
    print('No input is given.')
except KeyboardInterrupt:
    raw_input('Input x:')
    print('You, you! You know something.')

我知道这不一样,但很多现实生活中的问题可以通过这种方式解决。(如果用户不在场,我希望某些东西继续运行,我通常需要让用户输入超时。)

希望这至少能有所帮助。(如果有人读到的话:))

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用