在python中,有没有一种方法可以在等待用户输入时对时间进行计数,以便在30秒后自动跳过raw_input()函数?

评论

相关:Python 3定时输入/ 15528939

相关:Python / 1335507中带超时的键盘输入

相关:raw_input和超时/ 3471461

#1 楼

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

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。以相同的方式处理这两种情况(如果需要区分,您可以为计时器使用自己的函数,该函数在中断主线程之前记录某个地方发生了超时的事实,并在您的处理程序中KeyboardInterrupt访问“在某处”以区分发生两种情况。)

编辑:我本可以宣誓这是可行的,但我一定是错的-上面的代码忽略了显然需要的timer.start() ,即使有了它,我也无法使其正常工作。 select.select显然是另一种尝试,但是在Windows中的“普通文件”(包括stdin)上不起作用-在Unix中,它在Windows中的所有文件上都只能在套接字上工作。

所以我不知道如何做一个跨平台的“原始输入超时”。可以使用紧密循环轮询msvcrt.kbhit来构造特定于Windows的窗口,然后执行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 ;-)。

如果您不只是因为用户输入缓慢而超时(而不是根本不输入!-),则可以在每次成功输入字符后重新计算finishat。

评论


嗯,我对此表示赞同,但现在我对其进行了测试,它似乎不起作用:s。您仍然必须按Enter键(在Ubuntu Linux上为python 2.6.5)。

– catchmeifyoutry
2010年5月29日在1:57



是的我现在正在测试您的代码,我将其设置为5秒,但是就像catchmeifyoutry所说的那样,您仍然必须等到按下Enter键

–calccrypto
2010年5月29日下午2:06

python线程文档中还有一个有趣的注释:注意:线程与中断的交互很奇怪:KeyboardInterrupt异常将被任意线程接收。 (当信号模块可用时,中断总是转到主线程。)

– catchmeifyoutry
2010年5月29日下午2:29

@calccrypto,如果要使用不同于None的默认值,请将其添加为函数的参数;现在,我将其重新编码为仅Windows(但由于没有Windows,因此无法对其进行测试),并完成了操作,即使用户正在缓慢键入(而不是等待30秒),它也会在30秒后终止没有打字,这对我来说似乎是一个更明智的界面),尽管我也提到了如何轻松实现更合理的行为(您只需在成功读取每个键入的字符后重置截止日期,因此只需30秒的不活动状态会导致超时行为)。

– Alex Martelli
2010年5月29日下午3:28

linux代码不起作用,因为超时不起作用。

–悉尼
2014年5月22日12:39

#2 楼

我在博客文章中找到了解决此问题的方法。以下是该博客文章中的代码:

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


请注意:此代码仅适用于* nix操作系统。

评论


很酷,但不幸的是,由于某种原因,信号模块没有“ SIGALRM”属性

–calccrypto
2010年5月29日在1:36

@calccrypto,也许您在Windows上? signal.SIGALRM仅适用于Unix(请参阅我的答案)。

– Alex Martelli
2010年5月29日在1:49

是的,很抱歉,应该注意到这仅是Unix。

– jer
2010年5月29日在1:56

这似乎与其他示例一样具有相同的问题,即在超时到期之后,代码执行不会继续。您必须按Enter键。有谁解决了这个问题?

– MydKnight
15年6月18日在23:49

#3 楼

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

评论


这需要用户输入“输入” ..我似乎无法使其超时。

–幻术师
13年7月17日在18:09

我迟到了3年,但是:应该使用raw_input而不是输入(打印输出指示Python 2)。在time_up()中,除非在结束时调用os._exit(1),否则不会取消读取。这可能会有其他含义,但是要摆脱该控制台的读取并不容易。

–cdarke
15年8月26日在16:39

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


评论


您仍然必须按“确定”保存在该对话框中编写的所有内容。

–sync11
17年8月30日在9:08

#5 楼

一个需要进行定时数学测试的诅咒示例

#!/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)


#6 楼

在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