关于python:如何设置raw_input的时间限制

How to set time limit on raw_input

本问题已经有最佳答案,请猛点这里访问。

在python中,在等待用户输入时,是否有方法计算时间,以便在30秒后自动跳过raw_input()函数?


不幸的是,@jer推荐的解决方案所基于的signal.alarm函数只是unix。如果需要跨平台或特定于Windows的解决方案,可以基于threading.timer,而使用thread.interrupt_main从计时器线程向主线程发送KeyboardInterrupt。即。:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import thread
import threading

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

无论是30秒超时还是用户明确决定点击control-c放弃输入任何内容,这都不会返回任何结果,但以同样的方式处理这两种情况似乎是可以的(如果需要区分,您可以为计时器使用自己的函数,在中断主线程之前,在某个地方记录一个事实,即超时已经发生了,在您的KeyboardInterrupt访问处理程序中,"某处"用于区分发生了哪一种情况)。

编辑:我可以发誓这是可行的,但我一定是错了——上面的代码省略了明显需要的timer.start(),即使有了它,我也不能让它继续工作。select.select显然是另一种尝试,但它不能在Windows中的"普通文件"(包括stdin)上工作——在Unix中,它只能在Windows中的所有文件上工作,只能在套接字上工作。

所以我不知道如何做一个跨平台的"原始输入超时"。一个特定于Windows的系统可以通过一个紧密的循环轮询msvcrt.kbhit来构造,执行msvcrt.getche(并检查它是否是一个返回,以指示输出已完成,在这种情况下,它会脱离循环,否则会累积并持续等待),并在需要时检查超时时间。我无法测试,因为我没有Windows计算机(它们都是Mac和Linux计算机),但这里我建议使用未测试的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import msvcrt
import time

def raw_input_with_timeout(prompt, timeout=30.0):
    print prompt,    
    finishat = time.time() + timeout
    result = []
    while True:
        if msvcrt.kbhit():
            result.append(msvcrt.getche())
            if result[-1] == '
'
:   # or
, 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,但是有什么选择呢?提出例外?是否返回其他默认值?无论他想要什么样的替代品,他都能清楚地把它放在我的江户的位置上。

如果你不想因为用户打字慢而超时(相反,根本不想打字!-,您可以在每次成功输入字符后重新计算finishinat。


我在一篇博文中找到了解决这个问题的方法。这是那篇博文的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 '
Prompt timeout. Continuing...'

    signal.signal(signal.SIGALRM, signal.SIG_IGN)
    return ''

请注意:此代码仅适用于*nix oss。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
'

    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文档,您将非常清楚这段代码中发生了什么!!


input()函数用于等待用户输入内容(至少是[enter]键)。

如果您没有设置为使用input(),下面是一个使用tkinter的更轻的解决方案。在Tkinter中,对话框(和任何小部件)可以在给定时间后销毁。

下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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('
You entered this : '
, W_Input.data, end=2*'
'
)

else : print('
Nothing was entered
'
)


一个诅咒的例子,用于定时数学测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/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('
'
)

    stdscr.addstr('Elapsed Time: %i
'
%(time.time() - s))
    stdscr.addstr('This is the answer: %s
'
%answer)
    #stdscr.refresh() ##implied with the call to getch
    stdscr.addstr('Press any key to exit...')
curses.wrapper(main)

在Linux下,可以使用curses和getch函数,它是非阻塞的。参见GETCHE()

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

等待键盘输入x秒的函数(必须先初始化Curses窗口(win1)!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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