Python 3和Windows 7的定时输入

问题描述 投票:1回答:2

我正在寻找一种解决方案,以便在一定时间后使用户的输入超时。此代码应在5秒钟后打印“成功...”,而无需用户进行任何交互:

def input_with_timeout(timeout):

    print ("Hello, you can type and press enter to change 'ans' variable value or wait "+str(timeout)+" seconds and the program will continue")   
    ans=input()   #pass input after timeout
    return ans


s="mustnotchange"

s=input_with_timeout(5)

if s=="mustnotchange":
    print("Success, if you didn't just cheat by writing mustnotchange")
else:
    print("you answered : "+s+" variable value has changed")

我知道这个问题经常被问到,但是以下主题中提供的NONE解决方案在WINDOWS 7和Python 3(Windows 7“最终” SP1 64位和Python 3.6.8 64位)上有效。Python 3 Timed Input

How to set time limit on raw_input

Keyboard input with timeout?

raw_input and timeout

实际上,我正在使用“技巧”来避免这个问题:我使用os.startfile()启动了另一个python脚本,但是启动时它无法对输入做出反应。

如果没有任何可行的答案,做到这一点一定很困难(多处理,线程,队列...,但这在很多情况下肯定会有所帮助。

谢谢。

python python-3.x windows multithreading input
2个回答
1
投票
once进行跨平台提示超时。超时时,它将要求用户按Enter键,因此提示-线程可以干净地关闭。

删除影响_prompter_exit的部分将允许超时恢复而无需用户按下Enter键,其代价是使提示线程保持活动状态,直到整个过程退出为止。仅像@Mad Physicist建议的那样加入具有超时的提示线程是行不通的,因为它不会取消对input()调用本身的阻止。如果不使用特定于OS的库,则(AFAIK)无法在没有最终提供某种形式的输入的情况下唤醒等待input()的线程。

代码是我的答案的简化版本,允许在给定的时间范围内进行多次输入:

Taking in multiple inputs for a fixed time in Python

from threading import Thread, enumerate, Event from queue import Queue, Empty import time SENTINEL = None class PromptManager(Thread): def __init__(self, timeout): super().__init__() self.timeout = timeout self._in_queue = Queue() self._out_queue = Queue() self.prompter = Thread(target=self._prompter, daemon=True) self._prompter_exit = Event() def run(self): """Run worker-thread. Start prompt-thread, fetch passed input from in_queue and forward it to `._poll()` in MainThread. If timeout occurs before user-input, enqueue SENTINEL to unblock `.get()` in `._poll()`. """ self.prompter.start() try: txt = self._in_queue.get(timeout=self.timeout) except Empty: self._out_queue.put(SENTINEL) print(f"\n[{time.ctime()}] Please press Enter to continue.") # without usage of _prompter_exit() and Enter, the # prompt-thread would stay alive until the whole program ends self._prompter_exit.wait() else: self._out_queue.put(txt) def start(self): """Start manager-thread.""" super().start() return self._poll() def _prompter(self): """Prompting target function for execution in prompter-thread.""" self._in_queue.put(input(f"[{time.ctime()}] >$ ")) self._prompter_exit.set() def _poll(self): """Get forwarded inputs from the manager-thread executing `run()` and process them in the parent-thread. """ msg = self._out_queue.get() self.join() return msg

用于演示:

if __name__ == '__main__':

    pm = PromptManager(timeout=5)
    msg = pm.start()
    print(f"User input: {msg}")

    for i in range(3):
        print(f"[{time.ctime()}] Do something else. "
              f"Alive threads:{[t.name for t in enumerate()]}")
        time.sleep(1)

以触发超时运行:

[Tue Nov 26 20:50:47 2019] >$ 
[Tue Nov 26 20:50:52 2019] Please press Enter to continue.

User input: None
[Tue Nov 26 20:50:57 2019] Do something else. Alive threads:['MainThread']
[Tue Nov 26 20:50:58 2019] Do something else. Alive threads:['MainThread']
[Tue Nov 26 20:50:59 2019] Do something else. Alive threads:['MainThread']

Process finished with exit code 0

及时运行用户输入:

[Tue Nov 26 20:51:16 2019] >$ Hello
User input: Hello
[Tue Nov 26 20:51:19 2019] Do something else. Alive threads:['MainThread']
[Tue Nov 26 20:51:20 2019] Do something else. Alive threads:['MainThread']
[Tue Nov 26 20:51:21 2019] Do something else. Alive threads:['MainThread']

Process finished with exit code 0

最后,我修改了
@@ Darkonaut答案(谢谢!)
以匹配我的第一种情况,并在库pynput中添加了“模拟键盘”以自动按下“ Enter”。

请注意,这在终端机(Python 3.6.8和Windows 7 SP1)中有效,但是如果从IDLE开始,则不起作用。from threading import Thread, enumerate, Event from queue import Queue, Empty import time from pynput.keyboard import Key, Controller SENTINEL = None class PromptManager(Thread): def __init__(self, timeout): super().__init__() self.timeout = timeout self._in_queue = Queue() self._out_queue = Queue() self.prompter = Thread(target=self._prompter, daemon=True) self._prompter_exit = Event() def run(self): """Run worker-thread. Start prompt-thread, fetch passed input from in_queue and forward it to `._poll()` in MainThread. If timeout occurs before user-input, enqueue SENTINEL to unblock `.get()` in `._poll()`. """ self.prompter.start() try: txt = self._in_queue.get(timeout=self.timeout) except Empty: self._out_queue.put(SENTINEL) print(f"\n[{time.ctime()}] Please press Enter to continue.") # without usage of _prompter_exit() and Enter, the # prompt-thread would stay alive until the whole program ends keyboard = Controller() keyboard.press(Key.enter) keyboard.release(Key.enter) self._prompter_exit.wait() else: self._out_queue.put(txt) def start(self): """Start manager-thread.""" super().start() return self._poll() def _prompter(self): """Prompting target function for execution in prompter-thread.""" self._in_queue.put(input(f"[{time.ctime()}] >$ ")) self._prompter_exit.set() def _poll(self): """Get forwarded inputs from the manager-thread executing `run()` and process them in the parent-thread. """ msg = self._out_queue.get() self.join() return msg def input_with_timeout(default, timeout): print ("Hello, you can type and press enter to change 'ans' variable value or wait "+str(timeout)+" seconds and the program will continue") pm = PromptManager(timeout) ans= pm.start() if isinstance(ans, str): print("ok") return ans else: return default s="mustnotchange" s=input_with_timeout(s,5) if s=="mustnotchange": print("Success, if you didn't just cheat by writing mustnotchange") else: print("you answered : "+s+" variable value has changed") time.sleep(5)


1
投票
@@ Darkonaut答案(谢谢!)
© www.soinside.com 2019 - 2024. All rights reserved.