键盘输入超时?
- 2024-11-26 08:36:00
- admin 原创
- 143
问题描述:
您将如何提示用户输入某些内容但在 N 秒后超时?
Google 指向了有关该问题的邮件线程http://mail.python.org/pipermail/python-list/2006-January/533215.html,但似乎不起作用。发生超时的语句,无论是 asys.input.readline
还是timer.sleep()
,我总是得到:
<type 'exceptions.TypeError'>: [raw_]input expected at most 1 arguments, got 2
不知何故,except 未能捕获。
解决方案 1:
使用 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!"
解决方案 2:
您链接的示例是错误的,异常实际上是在调用警报处理程序时发生的,而不是在读取块时发生的。最好试试这个:
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
解决方案 3:
如果你不关心它是如何工作的,
pip install inputimeout
那么
from inputimeout import inputimeout, TimeoutOccurred
if __name__ == "__main__":
try:
c = inputimeout(prompt='hello
', timeout=3)
except TimeoutOccurred:
c = 'timeout'
print(c)
非常简单
https://pypi.org/project/inputimeout/
解决方案 4:
这不是一个 Python 解决方案,但是......
我在 CentOS (Linux) 下运行脚本时遇到了这个问题,对我的情况有用的方法是在子进程中运行 Bash“read -t”命令。我知道这是一种残酷的令人厌恶的黑客行为,但我对它的效果感到很愧疚,所以我想在这里与大家分享。
import subprocess
subprocess.call('read -t 30', shell=True)
我所需要的只是等待 30 秒,除非按下 ENTER 键。这很有效。
解决方案 5:
这是一个在 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
解决方案 6:
Paul 的答案不太管用。下面修改后的代码对我有用
Windows 7 x64
原始 CMD shell(例如,不是git-bash 或其他非 M$ shell)
——msvcrt
看来 git-bash 中什么都不起作用。
蟒蛇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)
解决方案 7:
我花了大约二十分钟的时间,所以我认为值得一试,把它贴在这里。不过,它直接基于 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()
解决方案 8:
以下代码对我有用。
我使用了两个线程,一个用于获取 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 "
Response :",t
print time.ctime()
解决方案 9:
这是一个使用线程的可移植且简单的 Python 3 解决方案。这是唯一一个对我有用的跨平台解决方案。
我尝试过的其他方法都遇到了问题:
使用 signal.SIGALRM:在 Windows 上不起作用
使用选择调用:在 Windows 上不起作用
强制终止进程(而不是线程):stdin 不能在新进程中使用(stdin 会自动关闭)
将 stdin 重定向到 StringIO 并直接写入 stdin:如果已经调用 input() ,则仍将写入先前的 stdin (请参阅https://stackoverflow.com/a/15055639/9624704)
from threading import Thread
class myClass:
_input = None
def __init__(self):
get_input_thread = Thread(target=self.get_input)
get_input_thread.daemon = True # Otherwise the thread won't be terminated when the main program terminates.
get_input_thread.start()
get_input_thread.join(timeout=20)
if myClass._input is None:
print("No input was given within 20 seconds")
else:
print("Input given was: {}".format(myClass._input))
@classmethod
def get_input(cls):
cls._input = input("")
return
解决方案 10:
对于 Linux,我更喜欢select
@Pontus 的版本。这里只有一个 python3 函数,就像在 shell 中一样read
:
import sys, select
def timeout_input(prompt, timeout=3, default=""):
print(prompt, end=': ', flush=True)
inputs, outputs, errors = select.select([sys.stdin], [], [], timeout)
print()
return (0, sys.stdin.readline().strip()) if inputs else (-1, default)
跑步
In [29]: timeout_input("Continue? (Y/n)", 3, "y")
Continue? (Y/n):
Out[29]: (-1, 'y')
In [30]: timeout_input("Continue? (Y/n)", 3, "y")
Continue? (Y/n): n
Out[30]: (0, 'n')
以及一个yes_or_no
函数
In [33]: yes_or_no_3 = lambda prompt: 'n' not in timeout_input(prompt + "? (Y/n)", 3, default="y")[1].lower()
In [34]: yes_or_no_3("Continue")
Continue? (Y/n):
Out[34]: True
In [35]: yes_or_no_3("Continue")
Continue? (Y/n): no
Out[35]: False
解决方案 11:
我的跨平台解决方案
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
解决方案 12:
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')
好吧,只需设置一个新的守护线程,并设置一个睡眠时间,无论你想要超时多少时间。我认为这很容易赶上 XD
解决方案 13:
已经过去好几年了,但万一有人像我最近尝试解决此类问题时遇到这种情况,有一个更简单、更快捷的方法可以使用func-timeout
包来实现。大多数 IDE 在使用前必须安装它;您可以通过 进行安装pip
。上面的链接是不言自明的,但我将给出一个如何实现它的示例。
from func_timeout import FunctionTimedOut, func_timeout
try:
ans = func_timeout(5, lambda: int(input('What is the sum of 2 and 3?
')))
print(ans)
except FunctionTimedOut:
print(5)
func_timeout
返回方法的值作为其参数,question()
在本例中为函数。它还允许函数所需的其他参数(请参阅文档)。如果设置的时间过去(此处为 5 秒),它会引发TimedOutException
并运行块中的代码except
。
解决方案 14:
类似于 Locane 的窗口:
import subprocess
subprocess.call('timeout /T 30')
解决方案 15:
修改后的 iperov 答案对我有用(python3 win10 2019-12-09)
iperov 的变更:
用 sstr 替换 str,因为 str 是 python 中的一个函数
添加导入
添加睡眠以降低 while 循环的 CPU 使用率(?)
添加 if 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('
...time left '+str(tleft)+'s
command:')
time.sleep(2)
p.terminate()
sys.stdin = os.fdopen( sys.stdin.fileno() )
return inp
if __name__=='__main__':
input_in_time("command:", 17)
解决方案 16:
您可以在 Python >= 3.4 中使用inputimeout lib。MIT 许可证。
$ pip install inputimeout
from inputimeout import inputimeout, TimeoutOccurred
try:
something = inputimeout(prompt='>>', timeout=5)
except TimeoutOccurred:
something = 'something'
print(something)
解决方案 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()
解决方案 18:
import datetime, time
def custom_time_input(msg, seconds):
try:
print(msg)
# current time in seconds
current_time = datetime.datetime.now()
time_after = current_time + datetime.timedelta(seconds=seconds)
while datetime.datetime.now() < time_after:
print("Time left: ", end="")
print(time_after - datetime.datetime.now(), end="
")
time.sleep(1)
print("
")
return True
except KeyboardInterrupt:
return False
res = custom_time_input("If you want to create a new config file PRESS CTRL+C within 20 seconds!", 20)
if res:
pass # nothing changed
else:
pass # do something because user pressed ctrl+c
解决方案 19:
解决方案受到 iperov 的答案的启发,希望它更清晰一些:
import multiprocessing
import sys
def input_with_timeout(prompt, timeout=None):
"""Requests the user to enter a code at the command line."""
queue = multiprocessing.Queue()
process = multiprocessing.Process(
_input_with_timeout_process, args=(sys.stdin.fileno(), queue, prompt),
)
process.start()
try:
process.join(timeout)
if process.is_alive():
raise ValueError("Timed out waiting for input.")
return queue.get()
finally:
process.terminate()
def _input_with_timeout_process(stdin_file_descriptor, queue, prompt):
sys.stdin = os.fdopen(stdin_file_descriptor)
queue.put(input(prompt))
解决方案 20:
这是一种 Python 3.8+(尽管它可以适应 Python 3.6+)跨平台方法,仅使用threading
(因此不multiprocessing
调用 shell 实用程序)。它旨在从命令行运行脚本,不太适合动态使用。
您可以按如下方式包装内置input
函数。 在这种情况下,我将内置名称重新定义input
为包装器,因为此实现要求所有调用都input
通过此路由。 (免责声明:这就是为什么它可能不是一个很好的主意,只是为了好玩而提出的一个不同的想法。)
import atexit
import builtins
import queue
import threading
def _make_input_func():
prompt_queue = queue.Queue(maxsize=1)
input_queue = queue.Queue(maxsize=1)
def get_input():
while (prompt := prompt_queue.get()) != GeneratorExit:
inp = builtins.input(prompt)
input_queue.put(inp)
prompt_queue.task_done()
input_thread = threading.Thread(target=get_input, daemon=True)
last_call_timed_out = False
def input_func(prompt=None, timeout=None):
"""Mimics :function:`builtins.input`, with an optional timeout
:param prompt: string to pass to builtins.input
:param timeout: how long to wait for input in seconds; None means indefinitely
:return: the received input if not timed out, otherwise None
"""
nonlocal last_call_timed_out
if not last_call_timed_out:
prompt_queue.put(prompt, block=False)
else:
print(prompt, end='', flush=True)
try:
result = input_queue.get(timeout=timeout)
last_call_timed_out = False
return result
except queue.Empty:
print(flush=True) # optional: end prompt line if no input received
last_call_timed_out = True
return None
input_thread.start()
return input_func
input = _make_input_func()
del _make_input_func
(我已经在一次性使用中定义了设置,_make_input_func
以在其闭包中隐藏input
“静态”变量,以避免污染全局命名空间。)
这里的想法是创建一个单独的线程来处理对 的所有调用builtins.input
,并让input
包装器管理超时。由于对 的调用builtins.input
始终阻塞直到有输入,因此当超时结束时,特殊线程仍在等待输入,但input
包装器返回(带有None
)。在下一次调用时,如果上次调用超时,则不需要builtins.input
再次调用(因为输入线程已经在等待输入),它只需打印提示,然后像往常一样等待所述线程返回一些输入。
定义完上述内容后,尝试运行以下脚本:
import time
if __name__ == '__main__':
timeout = 2
start_t = time.monotonic()
if (inp := input(f"Enter something (you have {timeout} seconds): ", timeout)) is not None:
print("Received some input:", repr(inp))
else:
end_t = time.monotonic()
print(f"Timed out after {end_t - start_t} seconds")
inp = input("Enter something else (I'll wait this time): ")
print("Received some input:", repr(inp))
input(f"Last chance to say something (you have {timeout} seconds): ", timeout)
解决方案 21:
有些答案要求Enter
在超时时按下该键才能继续运行代码。其他答案似乎很复杂,而且Enter
在超时后仍然需要按下该键。
我在另一个线程中找到了答案,它工作得很好,但我发现了一个警告。为了便于移植,我决定将我的代码放在一个class
。
笔记
我必须使用keyboard
来注入Enter
按键,因为input()
我的代码中还有另一个语句。出于某种原因,input()
除非我按下按键,否则后续语句不会出现Enter
。
import threading
import keyboard # https://github.com/boppreh/keyboard
class Utilities:
# Class variable
response = None
@classmethod
def user_input(cls, timeout):
def question():
cls.response = input("Enter something: ")
t = threading.Thread(target=question)
# Daemon property allows the target function to terminate after timeout
t.daemon = True
t.start()
t.join(timeout)
if cls.response:
# Do something
else:
# Do something else
# Optional. Use if you have other input() statements in your code
keyboard.send("enter")
用法
Utilities.user_input(3)
这是使用 Windows 10 上的 Python 3.8.3 制作的。
解决方案 22:
这是 Linux 上 Python 3.8+ 的另一个版本,其中包含一个 yes_no 答案,默认超时返回
import signal
def alarm_handler(signum, frame):
raise TimeoutError
def input_with_timeout(prompt, timeout=30):
""" get input with timeout
:param prompt: the prompt to print
:param timeout: timeout in seconds, or None to disable
:returns: the input
:raises: TimeoutError if times out
"""
# set signal handler
if timeout is not None:
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(timeout) # produce SIGALRM in `timeout` seconds
try:
return input(prompt)
except TimeoutError as to:
raise to
finally:
if timeout is not None:
signal.alarm(0) # cancel alarm
def yes_or_no(question, default='y', timeout=None):
""" Get y/n answer with default choice and optional timeout
:param question: prompt
:param default: the default choice, i.e. 'y' or 'n'
:param timeout: the timeout in seconds, default is None
:returns: True or False
"""
if default is not None and (default!='y' and default!='n'):
log.error(f'bad option for default: {default}')
quit(1)
y='Y' if default=='y' else 'y'
n='N' if default=='n' else 'n'
while "the answer is invalid":
try:
to_str='' if timeout is None else f'(Timeout {default} in {timeout}s)'
reply = str(input_with_timeout(f'{question} {to_str} ({y}/{n}): ',timeout=timeout)).lower().strip()
except TimeoutError:
log.warning(f'timeout expired, returning default={default} answer')
reply=''
if len(reply)==0:
return True if default=='y' else False
elif reply[0] == 'y':
return True
if reply[0] == 'n':
return False
代码使用示例
if yes_or_no(f'model {latest_model_folder} exists, start from it?', timeout=TIMEOUT):
log.info(f'initializing model from {latest_model_folder}')
model = load_model(latest_model_folder)
else:
log.info('creating new empty model')
model = create_model()
解决方案 23:
我正在使用外部工具inputimeout。源代码可在github上找到。我知道这是一个外部工具,但它很简单而且非常方便。安装该工具后,使用此代码:
from inputimeout import inputimeout, TimeoutOccurred
try:
something = inputimeout(prompt='>>', timeout=5)
except TimeoutOccurred:
something = 'No input.'
print(something)
解决方案 24:
扩展上一个使用inputtimeout的答案,并给出一个简单的例子
from inputimeout import inputimeout, TimeoutOccurred
def timed_input (user_prompt, timeout=5):
user_input = ""
timed_out = False
try:
user_input = inputimeout (prompt=user_prompt, timeout=timeout)
except TimeoutOccurred:
timed_out = True
return (timed_out, user_input)
timed_out, user_input = timed_input ("Enter something within 3s... ", timeout=3)
if timed_out:
print ("You failed to enter anything!")
else:
print (f"You entered {user_input}")
解决方案 25:
这是我写的代码。使用多处理,我们可以使输入超时。
from multiprocessing import Queue, Process
from queue import Empty
class ProcessTimedOutException(Exception):
def __init__(self, message: str):
self.message: str = message
class Terminal:
@staticmethod
def input_with_timeout(message: str = '', timeout: int = 60) -> Tuple[Optional[str], Optional[Exception]]:
queue = Queue()
err: Optional[Exception] = None
user_input: Optional[str] = None
input_thread = Process(target=Terminal._input_async, args=(queue, message), daemon=True)
input_thread.start()
try:
user_input = queue.get(timeout=timeout)
except Empty:
input_thread.terminate()
err = ProcessTimedOutException(f'process timed out')
return user_input, err
@staticmethod
def _input_async(queue, message: str = ''):
sys.stdin = open(0)
user_input = input(message).strip()
queue.put(user_input)
if __name__ == '__main__':
input_message: str = 'enter anything'
user_input, err = Terminal.input_with_timeout(message=input_message,timeout=60)
if err is not None:
raise err
print(user_input)
解决方案 26:
我遇到了同样的问题,并使用键盘和 kthread 解决了它。只要按下回车键,输入字段就会消失。这对我来说是最重要的事情,但我无法通过其他方法使其工作。
如果需要,你可以使用 pip 安装它:
pip install input-timeout
以下是一些示例:
from input_timeout import InputTimeout
i = InputTimeout(
timeout=20,
input_message=" >> ",
timeout_message="'Sorry, you were not fast enough'",
defaultvalue="slow",
cancelbutton="esc",
show_special_characters_warning='If you want to use special characters, you have to use alt+\\d\\d\\d\\d
Press "ctrl" to see a complete list of all combinations!',
).finalvalue
print(f"
Your input was {i}")
i = InputTimeout(
timeout=5,
input_message=" >> ",
timeout_message="Sorry, you were not fast enough: ",
defaultvalue="slow",
cancelbutton="esc",
show_special_characters_warning='If you want to use special characters, you have to use alt+\\d\\d\\d\\d
Press "ctrl" to see a complete list of all combinations!',
).finalvalue
print(f"
Your input was {i}")
i = InputTimeout(
timeout=10,
input_message=" >> ",
timeout_message="Sorry, you were not fast enough",
defaultvalue="Wake up!",
cancelbutton=None,
show_special_characters_warning=None,
).finalvalue
print(f"
Your input was {i}")
i = InputTimeout(
timeout=10,
input_message=" >> ",
timeout_message="Sorry, you were not fast enough",
defaultvalue="Are you sleeping?",
cancelbutton="esc",
show_special_characters_warning=None,
).finalvalue
print(f"
Your input was {i}")
i = InputTimeout(
timeout=10,
input_message=" >>",
timeout_message="Sorry, you were not fast enough",
defaultvalue="you are so slow",
cancelbutton=None,
show_special_characters_warning='If you want to use special characters, you have to use alt+\\d\\d\\d\\d
Press "ctrl" to see a complete list of all combinations!',
).finalvalue
print(f"
Your input was {i}")
#output
If you want to use special characters, you have to use alt+dddd
Press "ctrl" to see a complete list of all combinations!
>> babba
Your input was babba
If you want to use special characters, you have to use alt+dddd
Press "ctrl" to see a complete list of all combinations!
alt+0192 -> À alt+0193 -> Á alt+0196 -> Ä alt+0194 -> Â
alt+0195 -> Ã alt+0197 -> Å alt+0198 -> Æ alt+0228 -> ä
alt+0224 -> à alt+0225 -> á alt+0226 -> â alt+0227 -> ã
alt+0229 -> å alt+0230 -> æ alt+0199 -> Ç alt+0231 -> ç
alt+0208 -> Ð alt+0240 -> ð alt+0203 -> Ë alt+0200 -> È
alt+0201 -> É alt+0202 -> Ê alt+0235 -> ë alt+0232 -> è
alt+0233 -> é alt+0234 -> ê alt+0207 -> Ï alt+0204 -> Ì
alt+0205 -> Í alt+0206 -> Î alt+0239 -> ï alt+0236 -> ì
alt+0237 -> í alt+0238 -> î alt+0209 -> Ñ alt+0241 -> ñ
alt+0214 -> Ö alt+0210 -> Ò alt+0211 -> Ó alt+0212 -> Ô
alt+0213 -> Õ alt+0216 -> Ø alt+0140 -> Œ alt+0246 -> ö
alt+0242 -> ò alt+0243 -> ó alt+0244 -> ô alt+0245 -> õ
alt+0248 -> ø alt+0156 -> œ alt+0138 -> Š alt+0223 -> ß
alt+0154 -> š alt+0222 -> Þ alt+0254 -> þ alt+0220 -> Ü
alt+0217 -> Ù alt+0218 -> Ú alt+0219 -> Û alt+0252 -> ü
alt+0249 -> ù alt+0250 -> ú alt+0251 -> û alt+0159 -> Ÿ
alt+0221 -> Ý alt+0255 -> ÿ alt+0253 -> ý alt+0168 -> ¨
alt+0136 -> ˆ alt+0180 -> ´ alt+0175 -> ¯ alt+0184 -> ¸
alt+0192 -> À alt+0193 -> Á alt+0196 -> Ä alt+0194 -> Â
alt+0195 -> Ã alt+0197 -> Å alt+0198 -> Æ alt+0228 -> ä
alt+0224 -> à alt+0225 -> á alt+0226 -> â alt+0227 -> ã
alt+0229 -> å alt+0230 -> æ alt+0199 -> Ç alt+0231 -> ç
alt+0208 -> Ð alt+0240 -> ð alt+0203 -> Ë alt+0200 -> È
alt+0201 -> É alt+0202 -> Ê alt+0235 -> ë alt+0232 -> è
alt+0233 -> é alt+0234 -> ê alt+0207 -> Ï alt+0204 -> Ì
alt+0205 -> Í alt+0206 -> Î alt+0239 -> ï alt+0236 -> ì
alt+0237 -> í alt+0238 -> î alt+0209 -> Ñ alt+0241 -> ñ
alt+0214 -> Ö alt+0210 -> Ò alt+0211 -> Ó alt+0212 -> Ô
alt+0213 -> Õ alt+0216 -> Ø alt+0140 -> Œ alt+0246 -> ö
alt+0242 -> ò alt+0243 -> ó alt+0244 -> ô alt+0245 -> õ
alt+0248 -> ø alt+0156 -> œ alt+0138 -> Š alt+0223 -> ß
alt+0154 -> š alt+0222 -> Þ alt+0254 -> þ alt+0220 -> Ü
alt+0217 -> Ù alt+0218 -> Ú alt+0219 -> Û alt+0252 -> ü
alt+0249 -> ù alt+0250 -> ú alt+0251 -> û alt+0159 -> Ÿ
alt+0221 -> Ý alt+0255 -> ÿ alt+0253 -> ý alt+0168 -> ¨
alt+0136 -> ˆ alt+0180 -> ´ alt+0175 -> ¯ alt+0184 -> ¸
Sorry, you were not fast enough:
Your input was slow
>> super
Your input was super
>> adasa
Your input was adasa
If you want to use special characters, you have to use alt+dddd
Press "ctrl" to see a complete list of all combinations!
Sorry, you were not fast enough
Your input was you are so slow
解决方案 27:
2022 年 11 月, pypi 存储库中有一个名为的 Python 3 项目,由werecatfpytimedinput
编写。它在我的 Windows 10 系统上运行良好。您可以pip
像这样安装它:
C:UsersUser> pip install pytimedinput
以下是一个使用示例:
from pytimedinput import timedInput
userText, timedOut = timedInput("Enter something: ", timeout=5)
if(timedOut):
print("Timed out when waiting for input.")
print(f"User-input so far: '{userText}'")
else:
print(f"User-input: '{userText}'")
解决方案 28:
可以使用 asyncio 来实现这一点。本质上结合https://stackoverflow.com/a/65909044/3005167和https://stackoverflow.com/a/54787498/3005167会导致如下结果:
import asyncio
import sys
async def main():
reader = asyncio.StreamReader()
pipe = sys.stdin
loop = asyncio.get_event_loop()
await loop.connect_read_pipe(lambda: asyncio.StreamReaderProtocol(reader), pipe)
got_input = None
async def get_input():
nonlocal got_input
inp = await anext(aiter(reader))
got_input = inp.decode()
tasks = [asyncio.create_task(asyncio.sleep(5)), asyncio.create_task(get_input())]
await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
if got_input is None:
print("Time up!")
else:
print("Input: ", got_input)
if __name__ == "__main__":
asyncio.run(main())
解决方案 29:
我将重点介绍 Windows 解决方案,因为 Unix 解决方案已在此线程中多次提出(使用 API select
)。
一些解决方案建议使用该msvcrt.kbhit()
函数来检查是否有用户输入。仅当程序在交互式控制台中运行时,该函数才有效,并且它不处理使用基于管道的通信的多处理情况。我的解决方案依赖于直接使用pywin32
库的 Windows API:
import msvcrt
import time
import win32api, win32file, win32pipe
def input_timeout(timeout: float) -> str:
"""
Waits for specified period in seconds for user input. If user input is not received in time
function raises exception.
"""
start = time.time()
handle = win32api.GetStdHandle(win32api.STD_INPUT_HANDLE)
typ = win32file.GetFileType(handle)
buffer = ""
while (time.time() - start) < timeout:
# check the type of stdin handle
if typ == win32file.FILE_TYPE_PIPE:
# limited to 1024 bytes per line !!!
data, _, _ = win32pipe.PeekNamedPipe(handle, 1024)
# usage of CR or LF depends on what data you send to subprocess
if "
" in data:
return input()
else:
time.sleep(0.1)
else:
while msvcrt.kbhit():
ch = msvcrt.getwche()
if ch == "x08":
buffer = buffer[:-1]
# windows interactive console uses CR character (consider handling
too)
elif ch == "
":
print() # add missing LF
return buffer
# possibly other control characters need to be handled here
else:
buffer += ch
time.sleep(0.1)
print("Buffer:", repr(buffer))
raise TimeoutError()
# prompt
print("Enter value (you only have 2.5 seconds): ", end="", flush=True)
val = input_timeout(2.5)
print("Value entered:", val)
我个人建议使用专用线程通过回调来处理 stdin 输入。很多人尝试使用守护进程线程来处理 stdin,并且他们依赖系统在应用程序退出时终止线程,这显然是一种不好的做法 - 你总是需要清理你的烂摊子。这是我的解决方案:
import threading
import time
from typing import Callable, Optional
import win32api, win32event, win32file, win32pipe
def hook_input(callback: Callable[[str], None], keep_running: threading.Event) -> threading.Thread:
"""
Creates background thread that waits for input on stdin. When a new line is read from stdin
the callback is called with line read from stdin. You can use keep_running flag to terminate
background thread gracefully.
"""
def thread_fun(cb: Callable[[str], None], flag: threading.Event):
handle = win32api.GetStdHandle(win32api.STD_INPUT_HANDLE)
typ = win32file.GetFileType(handle)
while keep_running.is_set():
# WaitForSingleObject is not supported when stdin is pipe (e.g. when running as subprocess)
if typ == win32file.FILE_TYPE_PIPE:
# alternatively you can specify nonzero parameter to retrieve data in pipe buffer
# and check for LF character before calling input() function
_, available, _ = win32pipe.PeekNamedPipe(handle, 0)
if available > 0:
cb(input())
else:
time.sleep(0.1)
else:
# alternatively you cn use msvcrt.kbhit() with msvcrt.getwche() function, but you
# neet to handle control characters yourself (such as 0x08)
if win32event.WaitForSingleObject(handle, 100) == win32event.WAIT_OBJECT_0:
cb(input())
else:
time.sleep(0.1)
thread = threading.Thread(target=thread_fun, args=(callback, keep_running), daemon=False)
thread.start()
return thread
# hook input
flag = threading.Event()
flag.set()
thr = hook_input(lambda val: print("Received:", val), flag)
# do your stuff
# finish
flag.clear()
thr.join()
您还可以在回调函数中处理用户输入超时。asyncio
如果您将time.sleep()
函数替换为,则第二种实现可以安全地与库一起使用asyncio.sleep()
。请注意,在这种情况下将阻止事件循环运行,因此我建议您将短函数与长函数WaitForSingleObject()
结合使用。WaitForSingleObject()
`asyncio.sleep()`
解决方案 30:
回答晚了:)
我会做这样的事情:
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.')
我知道这不一样,但很多现实生活中的问题可以通过这种方式解决。(如果用户不在场,我希望某些东西继续运行,我通常需要让用户输入超时。)
希望这至少能有所帮助。(如果有人读到的话:))