Python 键盘输入超时?

Python 键盘输入超时?,python,timeout,keyboard-input,Python,Timeout,Keyboard Input,您将如何提示用户进行一些输入,但在N秒后超时 谷歌指向了一个关于它的邮件线程,但它似乎不起作用。发生超时的语句,无论是sys.input.readline还是timer.sleep(),我总是得到: :[raw_]输入最多需要1个参数,得到2个参数 不知何故,except无法捕获。您链接到的示例是错误的,异常实际上是在调用报警处理程序而不是在读取块时发生的。最好试试这个: import signal TIMEOUT = 5 # number of seconds your want for t

您将如何提示用户进行一些输入,但在N秒后超时

谷歌指向了一个关于它的邮件线程,但它似乎不起作用。发生超时的语句,无论是
sys.input.readline
还是
timer.sleep()
,我总是得到:

:[raw_]输入最多需要1个参数,得到2个参数

不知何故,except无法捕获。您链接到的示例是错误的,异常实际上是在调用报警处理程序而不是在读取块时发生的。最好试试这个:

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

使用select调用更短,而且应该更便于携带

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!"

这里有一个可以在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 
迟来的回答:)

我会这样做:

from time import sleep

print('Please provide input in 20 seconds! (Hit Ctrl-C to start)')
try:
    for i in range(0,20):
        sleep(1) # could use a backward counter to be preeety :)
    print('No input is given.')
except KeyboardInterrupt:
    raw_input('Input x:')
    print('You, you! You know something.')
#! /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()
我知道这是不一样的,但许多现实生活中的问题可以通过这种方式解决。(如果用户当时不在,我希望某些东西继续运行时,我通常需要用户输入超时。)


希望这至少有部分帮助。(如果有人读过:)

我花了大约二十分钟的时间在这上面,所以我觉得把它放在这里值得一试。不过,它直接基于用户137673的答案。我发现这样做最有用:

from time import sleep

print('Please provide input in 20 seconds! (Hit Ctrl-C to start)')
try:
    for i in range(0,20):
        sleep(1) # could use a backward counter to be preeety :)
    print('No input is given.')
except KeyboardInterrupt:
    raw_input('Input x:')
    print('You, you! You know something.')
#! /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()
#/usr/bin/env python
输入信号
超时=无
def main():
inp=stdinWait(“您有5秒钟的时间键入文本并按…”,“[无文本]”,5,“哦,伙计!您没时间了!!”)
如果没有超时:
打印“您输入的”,inp
其他:
打印“您没有输入任何内容,因为我的日程很紧!”
def stdinWait(文本、默认值、时间、超时显示=无,**kwargs):
signal.signal(signal.SIGALRM,中断)
信号。报警(时间)#设置超时
全局超时
尝试:
inp=原始输入(文本)
信号报警(0)
超时=错误
除了(键盘中断):
printInterrupt=kwargs.get(“printInterrupt”,True)
如果打印中断:
打印“键盘中断”
timeout=True#这样做可以避免在没有输入的情况下错误地获取输入
inp=默认值
除:
超时=真
如果不超时,则显示为无:
打印超时显示
信号报警(0)
inp=默认值
返回inp
def中断(信号、帧):
引发异常(“”)
如果名称=“\uuuuu main\uuuuuuuu”:
main()

不是Python解决方案,而是

我在CentOS(Linux)下运行脚本时遇到了这个问题,解决这个问题的方法是在子进程中运行Bash“read-t”命令。我知道这是一个残忍的骇人听闻的黑客行为,但我对它的工作效率感到内疚,我想和这里的每个人分享它

import subprocess
subprocess.call('read -t 30', shell=True)

我只需要等待30秒,除非按下回车键。这非常有效。

类似于Locane的windows:

import subprocess  
subprocess.call('timeout /T 30')

保罗的回答不太管用。下面修改的代码适用于我

  • windows 7 x64

  • 香草CMD shell(例如,git bash或其他非M$shell)

    --在git bash中,似乎没有任何东西可以工作

  • python 3.6

(我发布了一个新的答案,因为直接编辑Paul的答案会改变python 2.x-->3.x,这似乎太难编辑了(py2仍在使用)


下面的代码对我有用

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

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()

下面是一个使用线程的可移植且简单的Python3解决方案。 这是唯一一个在跨平台时对我有效的方法

我试过的其他东西都有问题:

  • 使用signal.SIGALRM:不在Windows上工作
  • 使用选择调用:不在Windows上工作
  • 使用进程的强制终止(而不是线程):stdin不能用于新进程(stdin自动关闭)
  • 将stdin重定向到StringIO并直接写入stdin:如果已调用input(),则仍将写入以前的stdin(请参阅)

我的跨平台解决方案

def input_process(stdin_fd, sq, str):
    sys.stdin = os.fdopen(stdin_fd)
    try:
        inp = input (str)
        sq.put (True)
    except:
        sq.put (False)

def input_in_time (str, max_time_sec):
    sq = multiprocessing.Queue()
    p = multiprocessing.Process(target=input_process, args=( sys.stdin.fileno(), sq, str))
    p.start()
    t = time.time()
    inp = False
    while True:
        if not sq.empty():
            inp = sq.get()
            break
        if time.time() - t > max_time_sec:
            break
    p.terminate()
    sys.stdin = os.fdopen( sys.stdin.fileno() )
    return inp
适用于我的修改过的iperov答案(python3 win10 2019-12-09) 对iperov的更改:
  • 将str替换为sstr,因为str是python中的一个函数

  • 添加导入

  • 添加睡眠以降低while循环的cpu使用率(?)

  • 如果name='main',则添加:#windows上的多处理所需

    导入系统、操作系统、多处理、时间

    def input_process(stdin_fd, sq, sstr):
        sys.stdin = os.fdopen(stdin_fd)
        try:
            inp = input(sstr)
            sq.put(True)
        except:
            sq.put(False)
    
    def input_in_time(sstr, max_time_sec):
        sq = multiprocessing.Queue()
        p = multiprocessing.Process(target=input_process, args=( sys.stdin.fileno(), sq, sstr))
        p.start()
        t = time.time()
        inp = False
        while True:
    
            if not sq.empty():
                inp = sq.get()
                break
            if time.time() - t > max_time_sec:
                break
    
            tleft=int( (t+max_time_sec)-time.time())
            if tleft<max_time_sec-1 and tleft>0:
                print('\n  ...time left '+str(tleft)+'s\ncommand:')
    
            time.sleep(2)
    
        p.terminate()
        sys.stdin = os.fdopen( sys.stdin.fileno() )
        return inp
    
    if __name__=='__main__':
        input_in_time("command:", 17)
    
    def输入过程(标准输入fd、sq、sstr):
    sys.stdin=os.fdopen(stdin\u fd)
    尝试:
    inp=输入(sstr)
    sq.put(真)
    除:
    sq.put(假)
    def输入时间(sstr,最大时间秒):
    sq=多处理。队列()
    p=multiprocessing.Process(target=input_Process,args=(sys.stdin.fileno(),sq,sstr))
    p、 开始()
    t=time.time()
    inp=False
    尽管如此:
    如果不是sq.empty():
    inp=sq.get()
    打破
    如果time.time()-t>最大时间秒:
    打破
    tleft=int((t+max_time_sec)-time.time())
    如果为0:
    打印('\n…左时间'+str(tleft)+'s\n命令:')
    时间。睡眠(2)
    p、 终止()
    sys.stdin=os.fdopen(sys.stdin.fileno())
    返回inp
    如果“名称”=“\uuuuuuuu主要”:
    输入输入时间(“命令:”,17)
    

这就是我处理这个问题的方式。我还没有对它进行彻底测试,我也不确定它是否存在一些重要问题,但考虑到其他解决方案也远远不够完美,我决定与大家分享:

import sys
import subprocess


def switch():
    if len(sys.argv) == 1:
        main()
    elif sys.argv[1] == "inp":
        print(input(''))
    else:
        print("Wrong arguments:", sys.argv[1:])


def main():
    passw = input_timed('You have 10 seconds to enter password:', timeout=10)
    if passw is None:
        print("Time's out! You explode!")
    elif passw == "PasswordShmashword":
        print("H-h-how did you know you h-h-hacker")
    else:
        print("I spare your life because you at least tried")


def input_timed(*args, timeout, **kwargs):
    """
    Print a message and await user input - return None if timedout
    :param args: positional arguments passed to print()
    :param timeout: number of seconds to wait before returning None
    :param kwargs: keyword arguments passed to print()
    :return: user input or None if timed out
    """
    print(*args, **kwargs)
    try:
        out: bytes = subprocess.run(["python", sys.argv[0], "inp"], capture_output=True, timeout=timeout).stdout
    except subprocess.TimeoutExpired:
        return None
    return out.decode('utf8').splitlines()[0]


switch()

对于Linux,我更喜欢@Pontus的
select
版本。这里只有一个python3函数在shell中的工作方式类似于
read

import sys,选择
def超时_输入(p
from threading import Thread
import time


def get_input():
    while True:
        print(input('> '))


t1 = Thread(target=get_input)
t1.setDaemon(True)
t1.start()
time.sleep(3)
print('program exceeds')
from inputimeout import inputimeout, TimeoutOccurred
try:
    something = inputimeout(prompt='>>', timeout=5)
except TimeoutOccurred:
    something = 'No input.'
print(something)