跳至内容

进度条

如果您正在执行可能需要一些时间的操作,您可以将其告知用户。🤓

进度条

您可以使用 Rich 的进度显示 来显示进度条,例如

import time

import typer
from rich.progress import track


def main():
    total = 0
    for value in track(range(100), description="Processing..."):
        # Fake processing time
        time.sleep(0.01)
        total += 1
    print(f"Processed {total} things.")


if __name__ == "__main__":
    typer.run(main)

您将要迭代的内容放在 Rich 的 track() 中,然后迭代它。

检查它

$ python main.py

---> 100%

Processed 100 things.

...实际上,它看起来会漂亮很多。✨ 但我无法在文档中向您展示动画。😅

颜色和信息将类似于以下内容

$ python main.py

Processing... <font color="#F92672">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸</font><font color="#3A3A3A">━━━━━━━━━━</font> <font color="#AE81FF"> 74%</font> <font color="#A1EFE4">0:00:01</font>

旋转器

当您不知道操作需要多长时间时,可以使用旋转器。

Rich 允许您以复杂和高级的方式显示许多内容。

例如,这将显示两个旋转器

import time

import typer
from rich.progress import Progress, SpinnerColumn, TextColumn


def main():
    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        transient=True,
    ) as progress:
        progress.add_task(description="Processing...", total=None)
        progress.add_task(description="Preparing...", total=None)
        time.sleep(5)
    print("Done!")


if __name__ == "__main__":
    typer.run(main)

我无法在文档中向您展示美丽的动画。😅

但在某个时间点,它将看起来像这样(想象它正在旋转)。🤓

$ python main.py

<font color="#A6E22E">⠹</font> Processing...
<font color="#A6E22E">⠹</font> Preparing...

您可以在 Rich 文档的进度显示部分 中了解更多信息。

Typer progressbar

如果可以,您应该使用如上所述的 **Rich**,它具有更多功能,更高级,并且可以更美观地显示信息。✨

提示

如果您可以使用 Rich,请使用上面的信息、Rich 文档,并跳过本页面的其余部分。😎

但是,如果您无法使用 Rich,Typer(实际上是 Click)提供了一个简单的实用程序来显示进度条。

信息

typer.progressbar() 直接来自 Click,您可以在 Click 的文档 中了解更多信息。

使用 typer.progressbar

提示

请记住,使用 Rich 来完成此操作会更好。😎

您可以使用 with 语句使用 typer.progressbar(),例如

with typer.progressbar(something) as progress:
    pass

您将要迭代的内容作为函数参数传递给 typer.progressbar()

import time

import typer


def main():
    total = 0
    with typer.progressbar(range(100)) as progress:
        for value in progress:
            # Fake processing time
            time.sleep(0.01)
            total += 1
    print(f"Processed {total} things.")


if __name__ == "__main__":
    typer.run(main)

因此,如果您有一个用户列表,这可能是

users = ["Camila", "Rick", "Morty"]

with typer.progressbar(users) as progress:
    pass

使用 typer.progressbar()with 语句为您提供了一个可以迭代的对象,就像您通常迭代的内容一样。

但是通过迭代这个对象 **Typer**(实际上是 Click),Click 会知道更新进度条。

users = ["Camila", "Rick", "Morty"]

with typer.progressbar(users) as progress:
    for user in progress:
        typer.echo(user)

提示

注意,代码块有两层。一层是 `with` 语句,另一层是 `for` 语句。

信息

这对于需要花费一些时间的操作非常有用。

在上面的例子中,我们使用 `time.sleep()` 来模拟这种情况。

检查它

$ python main.py

---> 100%

Processed 100 things.

设置进度条 `length`

提示

请记住,使用 Rich 来完成此操作会更好。😎

进度条是从可迭代对象的长度生成的(例如,用户列表)。

但是,如果长度不可用(例如,对于每次从 Web API 获取新用户的操作),你可以将显式的 `length` 传递给 `typer.progressbar()`。

import time

import typer


def iterate_user_ids():
    # Let's imagine this is a web API, not a range()
    for i in range(100):
        yield i


def main():
    total = 0
    with typer.progressbar(iterate_user_ids(), length=100) as progress:
        for value in progress:
            # Fake processing time
            time.sleep(0.01)
            total += 1
    print(f"Processed {total} user IDs.")


if __name__ == "__main__":
    typer.run(main)

检查它

$ python main.py

---> 100%

Processed 100 user IDs.

关于带有 `yield` 的函数

如果你以前没有见过类似 `yield` 的东西,那就是一个 "生成器"。

你可以使用 `for` 循环迭代这个函数,在每次迭代中,它会返回 `yield` 的值。

`yield` 就像一个 `return`,它可以多次返回值,并允许你在 `for` 循环中使用该函数。

例如

def iterate_user_ids():
    # Let's imagine this is a web API, not a range()
    for i in range(100):
        yield i

for i in iterate_user_ids():
    print(i)

将打印每个“用户 ID”(这里只是从 `0` 到 `99` 的数字)。

添加 `label`

提示

请记住,使用 Rich 来完成此操作会更好。😎

你也可以设置一个 `label`

import time

import typer


def main():
    total = 0
    with typer.progressbar(range(100), label="Processing") as progress:
        for value in progress:
            # Fake processing time
            time.sleep(0.01)
            total += 1
    print(f"Processed {total} things.")


if __name__ == "__main__":
    typer.run(main)

检查它

python main.py Processed 100 things.

手动迭代

如果你需要手动迭代某些东西并以不规则的方式更新进度条,你可以不传递可迭代对象,而是只传递一个 `length` 给 `typer.progressbar()`。

然后调用 `with` 语句中对象的 `.update()` 方法

import time

import typer


def main():
    total = 1000
    with typer.progressbar(length=total) as progress:
        for batch in range(4):
            # Fake processing time
            time.sleep(1)
            progress.update(250)
    print(f"Processed {total} things in batches.")


if __name__ == "__main__":
    typer.run(main)

检查它

python main.py Processed 100 things in batches.