键盘输入在Python中超时

pup*_*eno 53 python timeout keyboard-input

你会如何提示用户输入一些信息但是在N秒后超时?

谷歌在http://mail.python.org/pipermail/python-list/2006-January/533215.html上指向了一个关于它的邮件线程,但似乎没有用.超时发生的语句,无论是sys.input.readline还是timer.sleep(),我总是得到:

<type'exception.TypeError'>:[raw_]输入最多需要1个参数,得2

以某种方式,除了没有抓住.

Pon*_*tus 84

使用选择呼叫更短,并且应该更加便携

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!"
Run Code Online (Sandbox Code Playgroud)

  • 我刚测试过,这对Windows不起作用.Select是可用的,但是在windows上,select的输入只能是socket - sys.stdin,文件描述符是unix.我下次肯定会先测试一下. (35认同)
  • 该死.那么,自尊的程序员还是使用Windows呢?;)对于简单的用户输入,我想可以通过"kbhit"循环来检测键盘按下,"getch"和"time.sleep"在超时后中断.但它会很难看. (12认同)
  • 如果您打算在此调用后再次从标准输入读取,最好在读取超时的情况下执行“termios.tcflush(sys.stdin, termios.TCIFLUSH)”。否则,如果用户输入字符但未按 Enter 键,则终端仿真器可能允许用户按退格键并删除后续程序输出(最多为用户输入的字符数)。 (2认同)

use*_*673 31

您链接到的示例是错误的,并且在调用警报处理程序而不是读取块时实际发生异常.最好试试这个:

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
Run Code Online (Sandbox Code Playgroud)

  • 不错的解决方案,这只适用于Linux. (15认同)
  • 我正在尝试这个解决方案,但这在 python3 中不起作用。您必须在中断函数中引发错误才能在定义的输入函数中捕获该异常 - 这将使其在 python3 中工作。:) (6认同)
  • 这对我不起作用.它只是在5秒后打印"中断",但它实际上并没有停止`输入'.它仍然等待按下Enter键,它甚至会在出现"Interrupted"消息后打印我输入的任何文本.使用Python 2和3在Linux上测试. (4认同)

Loc*_*ane 11

不是Python解决方案,但......

我使用在CentOS(Linux)下运行的脚本来解决这个问题,对我的情况有用的只是在子进程中运行Bash"read -t"命令.我知道,野蛮恶心的黑客,但我对它的运作情况感到内疚,我想与大家分享.

import subprocess
subprocess.call('read -t 30', shell=True)
Run Code Online (Sandbox Code Playgroud)

除非按下ENTER键,否则我需要的是等待30秒的东西.这很有效.


Pau*_*aul 8

这是一个适用于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 
Run Code Online (Sandbox Code Playgroud)

  • 我刚刚意识到我不需要使用线程。在 http://stackoverflow.com/questions/3471461/raw-input-and-timeout/3911560#3911560 查看相同的代码但没有线程 (2认同)
  • 在 Python 3 中,用 print(prompt, end='',lush=True) 替换 sys.stdout.write 来打印提示。 (2认同)

小智 7

如果你不关心它是如何工作的,只是
pip install inputimeout

from inputimeout import inputimeout, TimeoutOccurred

if __name__ == "__main__":
    try:
        c = inputimeout(prompt='hello\n', timeout=3)
    except TimeoutOccurred:
        c = 'timeout'
    print(c)
Run Code Online (Sandbox Code Playgroud)

如此简单
https://pypi.org/project/inputimeout/

  • 仅供参考:PyPi 的链接有一个拼写错误,目前有开放的 PR (#6/#9) 来修复它。源代码在这里:https://github.com/johejo/inputimeout (2认同)

dyl*_*nmc 5

我花了大约 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()
Run Code Online (Sandbox Code Playgroud)


mik*_*ike 5

保罗的答案并不奏效.修改后的代码对我有用

  • Windows 7 x64

  • vanilla CMD shell(例如,不是 git-bash或其他非M $ shell)

    - 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) 
Run Code Online (Sandbox Code Playgroud)


小智 5

以下代码对我有用。

我使用了两个线程,一个用于获取 raw_Input,另一个用于等待特定时间。如果任何线程退出,则该线程都将终止并返回。

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()
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

70594 次

最近记录:

6 年,4 月 前