进度显示¶
Rich 可以显示关于长时间运行的任务/文件复制等的进度信息,这些信息会不断更新。 显示的信息是可配置的,默认情况下将显示“任务”的描述、进度条、完成百分比和估计剩余时间。
Rich 进度显示支持多个任务,每个任务都有一个进度条和进度信息。 你可以使用它来跟踪在线程或进程中进行的并发任务。
要查看进度显示的外观,请从命令行尝试以下操作
python -m rich.progress
注意
进度适用于 Jupyter 笔记本,但需要注意的是自动刷新功能已禁用。 你需要显式调用 refresh()
或在调用 update()
时设置 refresh=True
。 或者使用 track()
函数,该函数会在每次循环时自动刷新。
基本用法¶
对于基本用法,请调用 track()
函数,该函数接受一个序列(例如列表或范围对象)以及正在执行的作业的可选描述。 track 函数将从序列中生成值,并在每次迭代时更新进度信息。 以下是一个示例
import time
from rich.progress import track
for i in track(range(20), description="Processing..."):
time.sleep(1) # Simulate work being done
高级用法¶
如果你需要在显示中显示多个任务,或者希望配置进度显示中的列,你可以直接使用 Progress
类。 构建好 Progress 对象后,使用 (add_task()
) 添加任务,并使用 update()
更新进度。
Progress 类旨在用作上下文管理器,它会自动启动和停止进度显示。
以下是一个简单的示例
import time
from rich.progress import Progress
with Progress() as progress:
task1 = progress.add_task("[red]Downloading...", total=1000)
task2 = progress.add_task("[green]Processing...", total=1000)
task3 = progress.add_task("[cyan]Cooking...", total=1000)
while not progress.finished:
progress.update(task1, advance=0.5)
progress.update(task2, advance=0.3)
progress.update(task3, advance=0.9)
time.sleep(0.02)
与任务相关的total
值是进度达到 100% 所需完成的步骤数。 在这种情况下,步骤的含义取决于你的应用程序; 它可以是读取的文件字节数,或处理的图像数量等。
更新任务¶
当你调用 add_task()
时,你会得到一个任务 ID。 使用此 ID 在完成某些工作或任何信息发生变化时调用 update()
。 通常,你将需要在每次完成一个步骤时更新 completed
。 你可以通过直接更新 completed
或设置 advance
来实现,这将添加到当前的 completed
值。
The update()
方法收集关键字参数,这些参数也与任务相关。 使用它来提供你想在进度显示中渲染的任何其他信息。 附加参数存储在 task.fields
中,并且可以在 列类 中引用。
隐藏任务¶
你可以通过更新任务的 visible
值来显示或隐藏任务。 任务默认情况下是可见的,但你也可以通过调用 add_task()
并设置 visible=False
来添加一个不可见的任务。
瞬时进度¶
通常,当你退出进度上下文管理器(或调用 stop()
)时,最后刷新的显示会保留在终端中,光标位于下一行。 你也可以通过在 Progress 构造函数中设置 transient=True
使进度显示在退出时消失。 以下是一个示例
with Progress(transient=True) as progress:
task = progress.add_task("Working", total=100)
do_work(task)
瞬时进度显示在任务完成后,如果你希望终端输出更少时非常有用。
不确定进度¶
当你添加一个任务时,它会自动启动,这意味着它将显示一个 0% 的进度条,剩余时间将从当前时间开始计算。 如果在你可以开始更新进度之前存在很长的延迟,这可能不适用; 你可能需要等待服务器的响应或计算目录中的文件(例如)。 在这些情况下,你可以在调用 add_task()
时设置 start=False
或 total=None
,这将显示一个跳动的动画,让用户知道正在进行一些操作。 这称为不确定进度条。 当你有了步骤数量后,你可以调用 start_task()
,它将显示一个 0% 的进度条,然后像往常一样调用 update()
。
自动刷新¶
默认情况下,进度信息每秒刷新 10 次。 你可以在 Progress
构造函数上使用 refresh_per_second
参数来设置刷新频率。 如果你知道更新频率不会那么高,则应将其设置为低于 10 的值。
如果你知道更新频率不高,你可能希望完全禁用自动刷新,可以通过在构造函数上设置 auto_refresh=False
来实现。 如果你禁用了自动刷新,则需要在更新任务后手动调用 refresh()
。
扩展¶
进度条将仅使用终端宽度所需的宽度来显示任务信息。 如果你在 Progress 构造函数上设置了 expand
参数,那么 Rich 将会将进度显示拉伸到整个可用宽度。
列¶
你可以使用 Progress
构造函数的位置参数来自定义进度显示中的列。 列的指定方式是格式字符串或 ProgressColumn
对象。
格式字符串将使用单个值“task” 进行渲染,该值将是一个 Task
实例。 例如 "{task.description}"
将在列中显示任务描述,而 "{task.completed} of {task.total}"
将显示已完成的总步骤数。 通过关键字参数传递给~rich.progress.Progress.update 的附加字段将存储在 task.fields
中。 你可以使用以下语法将它们添加到格式字符串中:"extra info: {task.fields[extra]}"
。
默认列等效于以下列
progress = Progress(
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TaskProgressColumn(),
TimeRemainingColumn(),
)
要创建包含你自己的列的 Progress,除了默认列之外,请使用 get_default_columns()
progress = Progress(
SpinnerColumn(),
*Progress.get_default_columns(),
TimeElapsedColumn(),
)
以下列对象可用
BarColumn
显示进度条。TextColumn
显示文本。TimeElapsedColumn
显示经过时间。TimeRemainingColumn
显示估计剩余时间。MofNCompleteColumn
以"{task.completed}/{task.total}"
的形式显示完成进度(如果已完成和总数是整数,效果最佳)。FileSizeColumn
将进度显示为文件大小(假定步骤为字节)。TotalFileSizeColumn
显示总文件大小(假定步骤为字节)。DownloadColumn
显示下载进度(假定步骤为字节)。TransferSpeedColumn
显示传输速度(假定步骤为字节)。SpinnerColumn
显示“旋转器”动画。RenderableColumn
在列中显示任意的 Rich 可渲染对象。
要实现自己的列,请扩展 ProgressColumn
类并像使用其他列一样使用它。
表格列¶
Rich 为 Progress 实例中的任务构建一个 Table
。您可以通过在 Column 构造函数中指定 table_column
参数来定制此任务表的列的创建方式,该参数应该是一个 Column
实例。
以下示例演示了一个进度条,其中描述占据终端宽度的三分之一,进度条占据剩余的三分之二。
from time import sleep
from rich.table import Column
from rich.progress import Progress, BarColumn, TextColumn
text_column = TextColumn("{task.description}", table_column=Column(ratio=1))
bar_column = BarColumn(bar_width=None, table_column=Column(ratio=2))
progress = Progress(text_column, bar_column, expand=True)
with progress:
for n in progress.track(range(100)):
progress.print(n)
sleep(0.1)
打印/日志¶
Progress 类将创建一个内部 Console 对象,您可以通过 progress.console
访问它。如果您向此控制台打印或记录,输出将显示在进度显示上方。以下是一个示例
with Progress() as progress:
task = progress.add_task("twiddling thumbs", total=10)
for job in range(10):
progress.console.print(f"Working on job #{job}")
run_job(job)
progress.advance(task)
如果您要使用另一个 Console 对象,请将其传递给 Progress
构造函数。以下是一个示例
from my_project import my_console
with Progress(console=my_console) as progress:
my_console.print("[bold blue]Starting work!")
do_work(progress)
重定向 stdout/stderr¶
为了避免破坏进度显示的视觉效果,Rich 将重定向 stdout
和 stderr
,以便您可以使用内置的 print
语句。此功能默认情况下启用,但您可以通过将 redirect_stdout
或 redirect_stderr
设置为 False
来禁用它。
定制¶
如果 Progress
类没有提供您在进度显示方面需要的功能,您可以覆盖 get_renderables
方法。例如,以下类将在进度显示周围渲染一个 Panel
from rich.panel import Panel
from rich.progress import Progress
class MyProgress(Progress):
def get_renderables(self):
yield Panel(self.make_tasks_table(self.tasks))
从文件读取¶
Rich 提供了一种在读取文件时生成进度条的简单方法。如果您调用 open()
,它将返回一个上下文管理器,在您读取时显示进度条。当您无法轻松修改执行读取的代码时,这特别有用。
以下示例演示了如何在读取 JSON 文件时显示进度。
import json
import rich.progress
with rich.progress.open("data.json", "rb") as file:
data = json.load(file)
print(data)
如果您已经有一个文件对象,您可以调用 wrap_file()
,它将返回一个上下文管理器,它将您的文件包装起来,以便它显示进度条。如果您使用此函数,您将需要设置您预期读取的字节数或字符数。
以下是一个从互联网读取 url 的示例
from time import sleep
from urllib.request import urlopen
from rich.progress import wrap_file
response = urlopen("https://www.textualize.io")
size = int(response.headers["Content-Length"])
with wrap_file(response, size) as file:
for line in file:
print(line.decode("utf-8"), end="")
sleep(0.1)
如果您希望从多个文件读取,您可以使用 open()
或 wrap_file()
将文件进度添加到现有的 Progress 实例中。
请参阅 cp_progress.py <https://github.com/willmcgugan/rich/blob/master/examples/cp_progress.py>,了解 cp
命令的最小克隆,该命令在复制文件时显示进度条。
多个进度¶
您不能在单个 Progress 实例中为每个任务使用不同的列。但是,您可以在 实时显示 中使用任意多个 Progress 实例。请参阅 live_progress.py 和 dynamic_progress.py,了解使用多个 Progress 实例的示例。
示例¶
请参阅 downloader.py,了解进度显示的实际应用。此脚本可以使用进度条、传输速度和文件大小下载多个并发文件。