How to set time limit on raw_input

前端 未结 6 1529
抹茶落季
抹茶落季 2020-11-22 05:52

in python, is there a way to, while waiting for a user input, count time so that after, say 30 seconds, the raw_input() function is automatically skipped?

相关标签:
6条回答
  • 2020-11-22 06:21

    under linux one could use curses and getch function, its non blocking. see getch()

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

    function that waits for keyboard input for x seconds (you have to initialize a curses window (win1) first!

    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
    
    0 讨论(0)
  • 2020-11-22 06:27
    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
    

    As it is self defined... run it in command line prompt , I hope you will get the answer read this python doc you will be crystal clear what just happened in this code!!

    0 讨论(0)
  • 2020-11-22 06:28

    The signal.alarm function, on which @jer's recommended solution is based, is unfortunately Unix-only. If you need a cross-platform or Windows-specific solution, you can base it on threading.Timer instead, using thread.interrupt_main to send a KeyboardInterrupt to the main thread from the timer thread. I.e.:

    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
    

    this will return None whether the 30 seconds time out or the user explicitly decides to hit control-C to give up on inputting anything, but it seems OK to treat the two cases in the same way (if you need to distinguish, you could use for the timer a function of your own that, before interrupting the main thread, records somewhere the fact that a timeout has happened, and in your handler for KeyboardInterrupt access that "somewhere" to discriminate which of the two cases occurred).

    Edit: I could have sworn this was working but I must have been wrong -- the code above omits the obviously-needed timer.start(), and even with it I can't make it work any more. select.select would be the obvious other thing to try but it won't work on a "normal file" (including stdin) in Windows -- in Unix it works on all files, in Windows, only on sockets.

    So I don't know how to do a cross-platform "raw input with timeout". A windows-specific one can be constructed with a tight loop polling msvcrt.kbhit, performing a msvcrt.getche (and checking if it's a return to indicate the output's done, in which case it breaks out of the loop, otherwise accumulates and keeps waiting) and checking the time to time out if needed. I cannot test because I have no Windows machine (they're all Macs and Linux ones), but here the untested code I would suggest:

    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
    

    The OP in a comment says he does not want to return None upon timeout, but what's the alternative? Raising an exception? Returning a different default value? Whatever alternative he wants he can clearly put it in place of my return None;-).

    If you don't want to time out just because the user is typing slowly (as opposed to, not typing at all!-), you could recompute finishat after every successful character input.

    0 讨论(0)
  • 2020-11-22 06:36

    I found a solution to this problem in a blog post. Here's the code from that blog post:

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

    Please note: this code will only work on *nix OSs.

    0 讨论(0)
  • 2020-11-22 06:38

    A curses example which takes for a timed math test

    #!/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)
    
    0 讨论(0)
  • 2020-11-22 06:44

    The input() function is designed to wait for the user to enter something (at least the [Enter] key).

    If you are not dead set to use input(), below is a much lighter solution using tkinter. In tkinter, dialog boxes (and any widget) can be destroyed after a given time.

    Here is an example :

    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')
    
    0 讨论(0)
提交回复
热议问题