85

ユーザーに入力を求めるプロンプトを表示しますが、N秒後にタイムアウトしますか?

Googleはhttp://mail.python.org/pipermail/python-list/2006-January/533215.htmlでそれに関するメールスレッドを指していますが、機能していないようです。sys.input.readlineタイムアウトが発生するステートメントは、それがまたはであるかどうかに関係なくtimer.sleep()、常に次のようになります。

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

どういうわけか、例外はキャッチに失敗します。

4

23 に答える 23

111

選択呼び出しの使用は短く、はるかに移植性が高いはずです

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!"
于 2010-05-25T11:18:11.990 に答える
43

リンクした例は間違っており、ブロックを読み取るときではなく、アラームハンドラーを呼び出すときに例外が実際に発生しています。これを試してみてください:

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
于 2009-08-26T18:50:00.167 に答える
14

Pythonソリューションではありませんが、...

CentOS(Linux)で実行されているスクリプトでこの問題が発生しました。私の状況で機能したのは、サブプロセスでBashの「read-t」コマンドを実行することだけでした。残忍な嫌なハックは知っていますが、それがどれほどうまく機能したかについては十分に罪悪感を感じているので、ここのみんなと共有したいと思いました。

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

必要なのは、ENTERキーが押されない限り30秒間待つものだけでした。これはうまくいきました。

于 2014-12-01T06:23:49.220 に答える
11

それがどのように機能するかを気にしないのであれば
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/

于 2020-12-22T09:38:01.503 に答える
10

そしてこれが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 
于 2010-10-12T03:25:58.620 に答える
9

パウロの答えはうまくいきませんでした。以下の変更されたコードは私のために働きます

  • Windows 7 x64

  • バニラCMDシェル(例:git-bashやその他の非M $シェルではない)

    msvcrt--git-bashでは何も機能しません。

  • Python 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) 
于 2017-01-23T17:33:40.557 に答える
5

私はこれに20分ほどを費やしたので、これをここに置くことは一撃の価値があると思いました。ただし、これは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()
于 2014-09-16T04:59:11.703 に答える
5

次のコードは私のために働いた。

2つのスレッドを使用して1つはraw_Inputを取得し、もう1つは特定の時間待機しました。いずれかのスレッドが終了すると、両方のスレッドが終了して返されます。

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()
于 2017-03-23T12:22:52.300 に答える
4

これは、スレッドを使用したポータブルでシンプルなPython3ソリューションです。これは、クロスプラットフォームでありながら私のために働いた唯一のものです。

私が試した他のすべてのことには問題がありました:

  • 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
于 2019-01-09T13:13:48.463 に答える
3

私のクロスプラットフォームソリューション

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
于 2019-04-30T03:45:38.273 に答える
3

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
于 2019-12-26T01:56:25.103 に答える
3

Python>=3.4でinputimeoutlibを使用できます。MITライセンス。

$ pip install inputimeout

from inputimeout import inputimeout, TimeoutOccurred
try:
    something = inputimeout(prompt='>>', timeout=5)
except TimeoutOccurred:
    something = 'something'
print(something)
于 2021-07-19T18:21:22.193 に答える
2

Windows用のLocaneに類似しています:

import subprocess  
subprocess.call('timeout /T 30')
于 2016-09-08T12:23:07.817 に答える
1

私のために働く修正されたiperovの答え(python3 win10 2019-12-09)

iperovへの変更:

  • strはPythonの関数であるため、strをsstrに置き換えます

  • インポートを追加

  • whileループのCPU使用率を下げるためにスリープを追加します(?)

  • add if name ==' main ':#Windowsでのマルチプロセッシングに必要

    sys、os、マルチプロセッシング、時間のインポート

    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)
    
于 2019-12-09T19:18:36.083 に答える
1

これが私がこの問題に取り組んだ方法です。私はそれを徹底的にテストしていません、そしてそれがいくつかの重要な問題を持っているかどうかはわかりませんが、他の解決策も完璧にはほど遠いことを考慮して、私は共有することにしました:

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()
于 2019-12-11T13:23:24.710 に答える
1

もう何年も経っていますが、私が最近この種の問題を解決しようとしたように誰かがこれにぶつかった場合に備えて、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秒)、aが発生し、ブロックTimedOutException内のコードが実行されます。except

于 2020-04-09T10:21:37.643 に答える
1
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に追いつくのは簡単だと思います

于 2020-05-24T11:12:12.307 に答える
1

外部ツールinputimeoutを使用しています。ソースコードはgithubで入手できます。私はそれが外部ツールであることを知っていますが、それはシンプルで非常に便利です。ツールをインストールした後、次のコードを使用します。

from inputimeout import inputimeout, TimeoutOccurred
try:
    something = inputimeout(prompt='>>', timeout=5)
except TimeoutOccurred:
    something = 'No input.'
print(something)
于 2021-02-05T14:30:00.547 に答える
0

うまくいけば少しきれいな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))
于 2020-03-05T01:46:58.007 に答える
0

これは、Python 3.8以降(Python 3.6以降に適応できます)のクロスプラットフォームアプローチであり、使用するだけthreadingmultiprocessingです(つまり、シェルユーティリティを使用しないか呼び出します)。これは、コマンドラインからスクリプトを実行することを目的としており、動的な使用にはあまり適していません。

組み込み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を非表示にするために、1回限りのセットアップを定義しました。)input

ここでの考え方は、へのすべての呼び出しを処理する別のスレッドをbuiltins.input作成し、inputラッパーにタイムアウトを管理させることです。の呼び出しbuiltins.inputは入力があるまで常にブロックされるため、タイムアウトが終了しても、特別なスレッドは入力を待機していますが、inputラッパーは(with 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)
于 2020-07-25T18:57:23.233 に答える
0

一部の回答ではEnter、コードの実行を続行するために、タイムアウトが発生したときにキーを押す必要があります。他の人は複雑に見え、起動するには、Enterタイムアウト後にキーを押す必要があります。

は別のスレッドで答えを見つけました。これは美しく機能しますが、私が見つけた警告があります。class移植性のためにコードをに配置することにしました。

ノート

コードに別のステートメントが含まれていたため、キープレスkeyboardを挿入するために使用する必要がありました。何らかの理由で、キーを押さないと後続のステートメントが表示されませんでした。Enterinput()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)

これは、Windows10のPython3.8.3で作成されました。

于 2020-10-08T21:57:43.833 に答える
0

これがLinux上のpython3.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()
于 2020-11-03T19:06:21.407 に答える
-5

遅い答え:)

私はこのようなことをします:

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.')

私はこれが同じではないことを知っていますが、多くの現実の問題はこの方法で解決することができます。(通常、ユーザーが現在そこにいない場合に何かを実行し続けたい場合は、ユーザー入力のタイムアウトが必要です。)

これが少なくとも部分的に役立つことを願っています。(とにかく誰かがそれを読んだら:))

于 2012-03-14T15:50:21.353 に答える