Python CLI 进度 bar/spinner 没有迭代

Python CLI Progress bar/spinner WITHOUT iteration

在执行 Python 脚本时,关于终端中进度条显示的问题很多,但每一个问题都基于一个循环,您可以在循环中执行操作,然后更新进度图形.

不幸的是,我想显示其进度的函数——或者至少是一个微调器对象来显示它正在工作——是一个我不能(至少真的,真的不应该)的黑盒子改变。本质上,我想做的是:

#pseudocode input
print('Loading')
spinner.begin()
blackbox() #a few thousand operations happen in here
spinner.end()
print('Finished')

#pseudocode output
Loading.
Loading..
Loading...
Loading.
Loading..
Loading...
Finished

尽管理想情况下这将是省略号的动画而不是打印多行。在我什至可以开始构建愚蠢的 ascii 动画之前,有一个主要障碍:

有没有办法同时运行spinnerblackbox()?或者,是否有黑客可以暂停 blackbox(),无论其内容如何,​​每隔几百毫秒,更新微调器图形,然后从中断处恢复?

我已经用 progress 模块试过了,但没有成功...我什至无法让示例代码运行,它在我开始迭代后就挂了,直到我按 Ctrl+C出来了。

您可能想要使用线程 (import threading)。让 spinner.begin() 启动一个线程来打印您的消息,然后让您的黑盒 运行,然后让 spinner.end() 使用队列 (from Queue import Queue) 向线程发送完成消息或某事,join() 线程并继续做你正在做的事。

作为一种设计选择,将指纹隐藏在更深的地方,而不是与开始和结束调用位于同一代码块中。

Threads 可能是完成这项工作的最简单方法。这是一个大大简化的版本,应该可以理解这一点。我不确定你是否真的有 spinner 功能,所以我自己做了。

import threading
import time

def blackbox():
    time.sleep(10)

thread = threading.Thread(target=blackbox)
thread.start()

eli_count = 0
while thread.is_alive():
    print('Loading', '.'*(eli_count+1), ' '*(2-eli_count), end='\r')
    eli_count = (eli_count + 1) % 3
    time.sleep(0.1)
thread.join()
print('Done      ')

因此,在 blackbox 运行时,加载消息会定期更新。完成后,将加入线程并将加载消息替换为已完成的消息。

我喜欢为此使用 alive_progress

from typing import ContextManager, Optional
from alive_progress import alive_bar

def spinner(title: Optional[str] = None) -> ContextManager:
    """
    Context manager to display a spinner while a long-running process is running.

    Usage:
        with spinner("Fetching data..."):
            fetch_data()

    Args:
        title: The title of the spinner. If None, no title will be displayed.
    """
    return alive_bar(monitor=None, stats=None, title=title)

安装:pip install alive-progress