Ввод с клавиатуры с таймаутом в Python

Как бы вы предложили пользователю ввести некоторые данные, но не вышли бы через N секунд?

Google указывает на почтовую ветку об этом по адресу http://mail.python.org/pipermail/python-list/2006-January/533215.html но, похоже, не работает. Оператор, в котором происходит тайм-аут, независимо от того, является ли это sys.input.readline или timer.sleep(), я всегда получаю:

: вход [raw_] ожидается не более 1 аргумента, получено 2

который как-то, кроме как не может поймать.

31 ответ

Решение

Пример, на который вы ссылаетесь, неверен, и на самом деле исключение происходит при вызове обработчика тревоги, а не при чтении блоков. Лучше попробуйте это:

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

Использование вызова 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!"

если вам все равно, как это работает, просто
pip install inputimeout
а также

      from inputimeout import inputimeout, TimeoutOccurred

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

так просто
https://pypi.org/project/inputimeout/

Не решение Python, но...

Я столкнулся с этой проблемой с помощью скрипта, работающего под CentOS (Linux), и в моей ситуации работало только выполнение команды Bash "read -t" в подпроцессе. Зверский отвратительный взлом, я знаю, но я чувствую себя достаточно виноватым за то, насколько хорошо это сработало, и я хотел поделиться этим со всеми здесь.

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

Все, что мне было нужно, это что-то, что ждет 30 секунд, пока не будет нажата клавиша ENTER. Это сработало отлично.

А вот тот, который работает на Windows

Я не смог заставить ни один из этих примеров работать в Windows, поэтому я объединил несколько разных ответов Stackru, чтобы получить следующее:


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 

Ответ Павла не совсем сработал. Модифицированный код ниже, который работает для меня на

  • Windows 7 x64

  • ванильная оболочка CMD (например, не git-bash или другая оболочка не M$)

    -- ничего такого msvcrt работает в git-bash оказывается.

  • питон 3.6

(Я публикую новый ответ, потому что редактирование ответа Пола напрямую изменит его с 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) 

Я потратил на это около двадцати минут, так что я подумал, что это стоит того, чтобы поставить это здесь. Тем не менее, он напрямую строит ответ пользователя 137673. Я нашел наиболее полезным сделать что-то вроде этого:

#! /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()

Следующий код работал для меня.

Я использовал два потока, один для получения 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 "\nResponse :",t 
print time.ctime()

Для Linux я бы предпочел selectверсия от @Pontus. Здесь просто функция python3 работает как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

Вот переносимое и простое решение Python 3 с использованием потоков. Это единственный, который работал для меня, будучи кроссплатформенным.

У других вещей, которые я пробовал, были проблемы:

  • Использование signal.SIGALRM: не работает в Windows
  • Использование выбора вызова: не работает в Windows
  • Использование принудительного завершения процесса (вместо потока): stdin нельзя использовать в новом процессе (stdin автоматически закрывается)
  • Перенаправление stdin в StringIO и запись непосредственно в stdin: все равно будет писать в предыдущий stdin, если уже был вызван input() (см. /questions/46101420/zapisat-rezultat-funktsii-v-standartnyij-vvod/46101435#46101435)
    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
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')

Просто установите новый поток Daemon и установите время ожидания, которое вы хотите для тайм-аута. Я думаю, что XD легко догнать

Мое кроссплатформенное решение

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

Уже прошли годы, но на случай, если кто-то столкнется с этим, как я недавно пытался решить эту проблему, есть простой и быстрый способ добиться этого, используя 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?\n')))
   print(ans)
except FunctionTimedOut:
   print(5)

func_timeout возвращает значение метода в своем аргументе, question()функция в этом случае. Он также позволяет использовать другие аргументы, необходимые для функции (см. Документацию). По истечении установленного времени (здесь 5 секунд) появляетсяTimedOutException и запускает код в except блок.

Вы можете использовать в Python>= 3.4 библиотеку inputimeout . Лицензия MIT.

      $ pip install inputimeout

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

По аналогии с Locane's для окон:

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

Измененный ответ iperov, который работает для меня (python3 win10 2019-12-09)

изменения в иперов:

  • замените str на sstr, поскольку str - это функция в python

  • добавить импорт

  • добавить сон, чтобы снизить использование ЦП цикла while (?)

  • добавить if name=='main': #required для многопроцессорной обработки в Windows

    import sys, os, multiprocessing, time

    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('\n  ...time left '+str(tleft)+'s\ncommand:')
    
            time.sleep(2)
    
        p.terminate()
        sys.stdin = os.fdopen( sys.stdin.fileno() )
        return inp
    
    if __name__=='__main__':
        input_in_time("command:", 17)
    

Я использую внешний инструмент inputimeout . Исходный код доступен на github. Я знаю, что это внешний инструмент, но он простой и очень удобный. После установки инструмента используйте этот код:

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

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="\r")
            time.sleep(1)
        print("\n")
        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

Вот как я подошел к этой проблеме. Я не тестировал его тщательно, и я не уверен, что у него нет каких-то серьезных проблем, но, учитывая, что другие решения также далеки от совершенства, я решил поделиться:

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()

для этого есть библиотека от Массачусетского технологического института.

pip install inputimeout

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

Поскольку этот вопрос, кажется, служит дублирующим объектом, здесь ссылка на мой принятый ответ в дублирующем вопросе.

Характеристики

  • Независимо от платформы (Unix / Windows).
  • Только StdLib, без внешних зависимостей.
  • Только потоки, нет подпроцессов.
  • Немедленное прерывание по таймауту.
  • Чистое отключение суфлера по таймауту.
  • Неограниченные входы возможны в течение промежутка времени.
  • Легко расширяемый класс PromptManager.
  • Программа может возобновить работу после тайм-аута, возможен многократный запуск экземпляров подсказки без перезапуска программы.

Это кроссплатформенный подход Python 3.8+ (хотя его можно адаптировать к Python 3.6+), который использует толькоthreading (так что нет multiprocessingили вызовы утилит оболочки). Он предназначен для запуска скриптов из командной строки и не очень подходит для динамического использования.

Вы можете обернуть встроенный 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)

Решение, вдохновленное ответом 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))

У меня была такая же проблема, и я решил ее с помощью клавиатуры и 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\nPress "ctrl" to see a complete list of all combinations!',

        ).finalvalue

        print(f"\n\nYour 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\nPress "ctrl" to see a complete list of all combinations!',

        ).finalvalue

        print(f"\n\nYour 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"\n\nYour 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"\n\nYour 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\nPress "ctrl" to see a complete list of all combinations!',

        ).finalvalue

        print(f"\n\nYour input was {i}")

#output

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!

 >>  babba

Your input was babba

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!

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+\d\d\d\d

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

Sorry, you were not fast enough

Your input was you are so slow

Некоторые ответы требуют нажатия 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)

Это было сделано с помощью Python 3.8.3 в Windows 10.

Вот еще один Python 3.8+ в Linux, который включает ответ 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()

Это можно сделать с помощью asyncio. По сути, объединение /questions/11434685/slushajte-nazhatie-klavish-s-pomoschyu-asyncio/56902863#56902863 и /questions/4604527/kak-pravilno-ispolzovat-asynciofirstcompleted/4604537#4604537 приводит к чему-то вроде этого:

      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())

В ноябре 2022 года в репозитории pypi появился проект для Python 3 от werecatf под названиемpytimedinput. Он отлично работает в моей системе Windows 10. Вы можете установить его с помощьюpipтак:

      C:\Users\User> 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}'")

Расширение предыдущего ответа, в котором используется inputimeout, простой иллюстрацией.

      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}")

Это код, который я написал. Используя многопроцессорность, мы можем тайм-аут ввода.

      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)                    

Другие вопросы по тегам