警告:此代码仅适用于*nix和OSX系统,不支持Windows。
我使用了这个修改版的ActiveState recipe作为下面代码的基础。它是一个易于使用的对象,可以在超时时限内读取输入。它使用轮询一次收集一个字符,并模拟raw_input()
/ input()
的行为。
带有超时的输入
注意:显然下面的_getch_nix()
方法不适用于OP,但对我在OSX 10.9.5上有效。你可能需要尝试调用_getch_osx()
,但似乎只适用于32位python,因为Carbon不完全支持64位。
import sys
import time
class TimeoutInput(object):
def __init__(self, poll_period=0.05):
import sys, tty, termios
self.poll_period = poll_period
def _getch_nix(self):
import sys, tty, termios
from select import select
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
[i, o, e] = select([sys.stdin.fileno()], [], [], self.poll_period)
if i:
ch = sys.stdin.read(1)
else:
ch = ''
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
def _getch_osx(self):
import Carbon
if Carbon.Evt.EventAvail(0x0008)[0] == 0:
return ''
else:
(what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
return chr(msg & 0x000000FF)
def input(self, prompt=None, timeout=None,
extend_timeout_with_input=True, require_enter_to_confirm=True):
"""timeout: float seconds or None (blocking)"""
prompt = prompt or ''
sys.stdout.write(prompt)
sys.stdout.flush()
input_chars = []
start_time = time.time()
received_enter = False
while (time.time() - start_time) < timeout:
c = self._getch_osx()
if c in ('\n', '\r'):
received_enter = True
break
elif c:
input_chars.append(c)
sys.stdout.write(c)
sys.stdout.flush()
if extend_timeout_with_input:
start_time = time.time()
sys.stdout.write('\n')
sys.stdout.flush()
captured_string = ''.join(input_chars)
if require_enter_to_confirm:
return_string = captured_string if received_enter else ''
else:
return_string = captured_string
return return_string
测试它
ti = TimeoutInput(poll_period=0.05)
s = ti.input(prompt='wait for timeout:', timeout=5.0,
extend_timeout_with_input=False, require_enter_to_confirm=False)
print(s)
重复输入
根据我的理解,这实现了您的原始意图。我认为没有必要进行递归调用 - 我想你只是想要重复获取输入?如果我理解错了,请纠正我。
ti = TimeoutInput()
prompt = "Hello is it me you're looking for?"
timeout = 4.0
while True:
s = ti.input(prompt, timeout)
if s.lower() == 'q':
print "goodbye"
break