23

Pythonでは、ユーザー入力を待っている間に時間をカウントして、たとえば30秒後にraw_input()関数が自動的にスキップされるようにする方法はありますか?

4

7 に答える 7

34

@jerの推奨ソリューションが基づいているsignal.alarm関数は、残念ながらUnixのみです。クロスプラットフォームまたはWindows固有のソリューションが必要な場合は、代わりにthreading.Timerに基づいて、 thread.interrupt_mainKeyboardInterruptを使用してタイマースレッドからメインスレッドにを送信できます。すなわち:

import thread
import threading

def raw_input_with_timeout(prompt, timeout=30.0):
    print(prompt, end=' ')    
    timer = threading.Timer(timeout, thread.interrupt_main)
    astring = None
    try:
        timer.start()
        astring = input(prompt)
    except KeyboardInterrupt:
        pass
    timer.cancel()
    return astring

これは、30秒のタイムアウトか、ユーザーがcontrol-Cを押して何かの入力をあきらめることを明示的に決定したかにかかわらず、Noneを返しますが、2つのケースを同じように扱うことは問題ないようです(区別する必要がある場合は、タイマーの場合、メインスレッドに割り込む前に、タイムアウト発生したという事実をどこかに記録し、ハンドラーにKeyboardInterruptその「どこか」にアクセスして2つのケースのどちらが発生したかを区別する独自の関数)。

編集:私はこれが機能していることを誓ったかもしれませんが、私は間違っていたに違いありません-上記のコードは明らかに必要なものを省略しており、timer.start()それでもそれを機能させることはできません。 他に試してみるのは明らかですが、Windowsの「通常のファイル」(stdinを含む)では機能しません。Unixでは、すべてのファイルで機能し、Windowsではソケットでのみ機能します。select.select

だから私はクロスプラットフォームの「タイムアウト付きの生の入力」を行う方法がわかりません。ウィンドウ固有のものは、msvcrt.kbhitをポーリングし、msvcrt.getche(出力が完了したことを示すためのリターンであるかどうかをチェックします。その場合、ループから抜け出し、そうでない場合は累積して待機し続けます)を実行し、チェックするタイトループで構築できます。必要に応じてタイムアウトする時間。私はWindowsマシンを持っていないのでテストできません(それらはすべてMacとLinuxのマシンです)が、ここではテストされていないコードを提案します:

import msvcrt
import time

def raw_input_with_timeout(prompt, timeout=30.0):
    print(prompt, end=' ')    
    finishat = time.time() + timeout
    result = []
    while True:
        if msvcrt.kbhit():
            result.append(msvcrt.getche())
            if result[-1] == '\r':   # or \n, whatever Win returns;-)
                return ''.join(result)
            time.sleep(0.1)          # just to yield to other processes/threads
        else:
            if time.time() > finishat:
                return None

return NoneコメントのOPは、タイムアウト時にしたくないと言っていますが、代替手段は何ですか?例外を発生させますか?別のデフォルト値を返しますか?彼が望むどんな選択肢でも、彼は私の代わりにそれをはっきりと置くことができますreturn None;-)。

ユーザーがゆっくりと入力しているという理由だけでタイムアウトしたくない場合は(まったく入力しないのではなく!-)、文字入力が成功するたびにfinishatを再計算できます。

于 2010-05-29T01:41:29.423 に答える
13

私はブログ投稿でこの問題の解決策を見つけました。そのブログ投稿のコードは次のとおりです。

import signal

class AlarmException(Exception):
    pass

def alarmHandler(signum, frame):
    raise AlarmException

def nonBlockingRawInput(prompt='', timeout=20):
    signal.signal(signal.SIGALRM, alarmHandler)
    signal.alarm(timeout)
    try:
        text = raw_input(prompt)
        signal.alarm(0)
        return text
    except AlarmException:
        print '\nPrompt timeout. Continuing...'
    signal.signal(signal.SIGALRM, signal.SIG_IGN)
    return ''

注意:このコードは*nixOSでのみ機能します。

于 2010-05-29T01:32:22.307 に答える
4
from threading import Timer


def input_with_timeout(x):    

def time_up():
    answer= None
    print('time up...')

t = Timer(x,time_up) # x is amount of time in seconds
t.start()
try:
    answer = input("enter answer : ")
except Exception:
    print('pass\n')
    answer = None

if answer != True:   # it means if variable have somthing 
    t.cancel()       # time_up will not execute(so, no skip)

input_with_timeout(5) # try this for five seconds

それは自己定義されているので...コマンドラインプロンプトで実行してください。このPythonドキュメントを読んで答えが得られることを願っています。このコードで何が起こったのかが明確になります。

于 2012-10-17T21:35:41.520 に答える
4

input()関数は、ユーザーが何かを入力するのを待つように設計されています(少なくとも[Enter]キー)。

input()を使用するように完全に設定されていない場合は、tkinterを使用したはるかに軽いソリューションを以下に示します。tkinterでは、ダイアログボックス(および任意のウィジェット)は一定時間後に破棄される可能性があります。

次に例を示します。

import tkinter as tk

def W_Input (label='Input dialog box', timeout=5000):
    w = tk.Tk()
    w.title(label)
    W_Input.data=''
    wFrame = tk.Frame(w, background="light yellow", padx=20, pady=20)
    wFrame.pack()
    wEntryBox = tk.Entry(wFrame, background="white", width=100)
    wEntryBox.focus_force()
    wEntryBox.pack()

    def fin():
        W_Input.data = str(wEntryBox.get())
        w.destroy()
    wSubmitButton = tk.Button(w, text='OK', command=fin, default='active')
    wSubmitButton.pack()

# --- optionnal extra code in order to have a stroke on "Return" equivalent to a mouse click on the OK button
    def fin_R(event):  fin()
    w.bind("<Return>", fin_R)
# --- END extra code --- 

    w.after(timeout, w.destroy) # This is the KEY INSTRUCTION that destroys the dialog box after the given timeout in millisecondsd
    w.mainloop()

W_Input() # can be called with 2 parameter, the window title (string), and the timeout duration in miliseconds

if W_Input.data : print('\nYou entered this : ', W_Input.data, end=2*'\n')

else : print('\nNothing was entered \n')
于 2015-06-19T23:54:16.823 に答える
1

時限数学テストにかかる呪いの例

#!/usr/bin/env python3

import curses
import curses.ascii
import time

#stdscr = curses.initscr() - Using curses.wrapper instead
def main(stdscr):
    hd = 100 #Timeout in tenths of a second
    answer = ''

    stdscr.addstr('5+3=') #Your prompt text

    s = time.time() #Timing function to show that solution is working properly

    while True:
        #curses.echo(False)
        curses.halfdelay(hd)
        start = time.time()
        c = stdscr.getch()
        if c == curses.ascii.NL: #Enter Press
            break
        elif c == -1: #Return on timer complete
            break
        elif c == curses.ascii.DEL: #Backspace key for corrections. Could add additional hooks for cursor movement
            answer = answer[:-1]
            y, x = curses.getsyx()
            stdscr.delch(y, x-1)
        elif curses.ascii.isdigit(c): #Filter because I only wanted digits accepted
            answer += chr(c)
            stdscr.addstr(chr(c))
        hd -= int((time.time() - start) * 10) #Sets the new time on getch based on the time already used

    stdscr.addstr('\n')

    stdscr.addstr('Elapsed Time: %i\n'%(time.time() - s))
    stdscr.addstr('This is the answer: %s\n'%answer)
    #stdscr.refresh() ##implied with the call to getch
    stdscr.addstr('Press any key to exit...')
curses.wrapper(main)
于 2017-01-11T04:14:58.503 に答える
0

Linuxでは、cursesとgetch関数を使用できます。これはノンブロッキングです。getch()を参照してください

https://docs.python.org/2/library/curses.html

キーボード入力をx秒間待機する関数(最初にcursesウィンドウ(win1)を初期化する必要があります!

import time

def tastaturabfrage():

    inittime = int(time.time()) # time now
    waitingtime = 2.00          # time to wait in seconds

    while inittime+waitingtime>int(time.time()):

        key = win1.getch()      #check if keyboard entry or screen resize

        if key == curses.KEY_RESIZE:
            empty()
            resize()
            key=0
        if key == 118:
            p(4,'KEY V Pressed')
            yourfunction();
        if key == 107:
            p(4,'KEY K Pressed')
            yourfunction();
        if key == 99:
            p(4,'KEY c Pressed')
            yourfunction();
        if key == 120:
            p(4,'KEY x Pressed')
            yourfunction();

        else:
            yourfunction

        key=0
于 2016-10-09T07:41:54.440 に答える
0

これは新しいPythonバージョン用ですが、それでも質問に答えられると思います。これは、時間切れであることをユーザーに通知するメッセージを作成してから、コードを終了します。コードを完全に終了するのではなく、入力をスキップする方法があると確信していますが、どちらにしても、これは少なくとも役立つはずです...

import sys
import time
from threading import Thread
import pyautogui as pag
#imports the needed modules

xyz = 1 #for a reference call

choice1 = None #sets the starting status

def check():
    time.sleep(15)#the time limit set on the message
    global xyz
    if choice1 != None:  # if choice1 has input in it, than the time will not expire
        return
    if xyz == 1:  # if no input has been made within the time limit, then this message 
                  # will display
        pag.confirm(text = 'Time is up!', title = 'Time is up!!!!!!!!!')
        sys.exit()


Thread(target = check).start()#starts the timer
choice1 = input("Please Enter your choice: ")

于 2021-05-17T20:52:16.040 に答える