Python 键盘输入超时?
您将如何提示用户进行一些输入,但在N秒后超时 谷歌指向了一个关于它的邮件线程,但它似乎不起作用。发生超时的语句,无论是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
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
下面的代码对我有用 我使用了两个线程,一个用于获取原始输入,另一个用于等待特定时间。 如果任何线程退出,则终止并返回两个线程
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)