如何让用户在预定义的位置暂停python脚本?

时间:2019-05-23 13:47:41

标签: python

说我有很多工作要做,所以我想让用户选择暂停和/或停止工作。 但是我不想以不一致的状态结束,所以我只能在程序中的某些点暂停并退出。

我将如何实现一种user_requested_pause()方法,该方法可以按如下方式使用?

for item in some_very_large_list:
  do_work()
  # can't stop here
  do_more_work()
  # now we could pause.
  if user_requested_pause():
    # ask user how to proceed, then continue or exit with consistent state

我考虑过只使用ctrl + c,但是KeyboardInterrupt可以随时出现。

理想情况下,我会检查stdin上是否有可用的输入,但是我还没有找到一种方法。 read()仅在没有输入的情况下才会阻塞,即使用户不希望它也可以暂停程序。

编辑:我如下解决了该问题:

import signal
pause_requested = False
def handler(signum, frame):
  global pause_requested
  pause_requested = True
for item in some_very_large_list:
  do_work()
  do_more_work()
  if pause_requested:
    # ask user how to proceed, then continue or exit with consistent state
    pause_requested = False

4 个答案:

答案 0 :(得分:1)

您可以查看asyncio库。特别是如果您具有awaitable函数来捕获键盘输入。

答案 1 :(得分:1)

通过使处理程序设置一个标志来告知程序暂停并等待输入,您也许可以使用the signal module

答案 2 :(得分:1)

您可以使用多线程来为工作分配一个单独的线程,并定期检查状态变量requested_pause。然后,主线程在请求​​使用input()的循环中运行,并在有条目时相应地设置requested_pause

答案 3 :(得分:0)

如果要在没有用户干预的情况下继续执行(而不是默认情况下暂停(要求用户重新启动))的最佳解决方案,则需要使用辅助线程,协程或进程来接受用户输入并进行某种排序告诉主处理线程暂停的标志。这可以通过很多方法来实现,但是我将仅使用python标准库和内置函数进行演示。其他方法可能更灵活(例如,检测特定的按键或使用图形界面而不是命令行),但会很快遇到兼容性问题,因为检测硬件输入通常是使用GUI库完成的,并且通常在系统之间略有不同。像keyboard这样的一些库非常好,但是即使这个库也有一个警告(在Linux上需要root)。

使用线程等待input()功能(用户按下Enter)的示例代码:

import threading, time

class user_input_thread(threading.Thread):
    def __init__(self, event_obj):
        super().__init__()
        self.daemon = True
        self.event_obj = event_obj

    def run(self):
        while True:

            self.event_obj.wait() #wait for the user to resume processing from main thread
            print('process resumed')
            input('press enter to pause\n') #use raw_input() for python 2.x
            print('process will pause')
            self.event_obj.clear() #clear the flag forcing processing to stop

def main_work(event_obj, *args):
    for x in range(10):
        if not event_obj.is_set():
            input('press enter to resume') #use raw_input() for python 2.x
            event_obj.set()
        time.sleep(2) #heavy computation that can't be interrupted
        print('done with task {}'.format(x))

if __name__ == '__main__':
    event_obj = threading.Event() #work starts paused
    user_input_thread(event_obj).start()
    main_work(event_obj)

由于纯python的某些局限性,所以这不是一个完美的解决方案,因为线程(即使它是守护程序)在程序末尾不会退出,因为它仍在等待用户输入。这要求您按Enter键以终止程序(尽管所有工作都将完成,并且解释器将在文件末尾等待)。通过打印语句的附加用户指令和一些附加的控制逻辑可以使此操作更好,但不会在很大程度上改变功能。另一种选择是将try: except:放在主文件中的循环中,该标志设置/清除一个标志,该标志表示进行主工作的辅助线程经常检查一次。