質問

ユーザーに入力を求めるプロンプトが表示され、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

どういうわけか例外はキャッチできません。

役に立ちましたか?

解決

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

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

他のヒント

を選択し、コールが短い使用して、そしてはるかに移植する必要があります。

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!"

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

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

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

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

そして、ここで、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 

ポールの答えはうまくいきませんでした。私にとって機能する以下の変更されたコード

  • ウィンドウズ7x64

  • バニラ 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) 

私はこれで良い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()

次のコードは、私のために働いています。

私は1つがraw_Inputを取得するには、別の特定の時間を待つために2つのスレッドを使用していました。 スレッドが終了するのいずれかの場合は、スレッドの両方が終了して返されます。

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

Locaneの窓のために類似します:

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

これは、スレッドを使用した移植可能でシンプルな 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

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

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

後半の答え:)

私はこのような何かをするだろう

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

私は、これは同じですが、多くの現実の問題がこのように解決することができないことを知っています。 (私は、もしユーザーがいないが、現時点では実行を継続するために何かをしたいとき、私は通常、ユーザー入力のタイムアウトを必要としています。)

が、これは、少なくとも部分的にお役に立てば幸いです。 (誰がとにかくそれを読み取る場合:))

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top