跳至内容

打印和颜色

你可以使用普通的 print() 在屏幕上显示信息

import typer


def main():
    print("Hello World")


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

它将正常显示输出

$ python main.py

Hello World

使用 Rich

你还可以使用 Rich 显示美观且更复杂的信息。当你安装 typer 时,它会默认安装。

使用 Rich print

对于最简单的情况,你可以从 rich 导入 print,然后使用它来代替标准的 print

import typer
from rich import print

data = {
    "name": "Rick",
    "age": 42,
    "items": [{"name": "Portal Gun"}, {"name": "Plumbus"}],
    "active": True,
    "affiliation": None,
}


def main():
    print("Here's the data")
    print(data)


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

有了它,Rich 就能以漂亮的颜色和结构打印您的数据

$ python main.py

Here's the data
<b>{</b>
    <font color="#A6E22E">&apos;name&apos;</font>: <font color="#A6E22E">&apos;Rick&apos;</font>,
    <font color="#A6E22E">&apos;age&apos;</font>: <font color="#A1EFE4"><b>42</b></font>,
    <font color="#A6E22E">&apos;items&apos;</font>: <b>[</b>
        <b>{</b><font color="#A6E22E">&apos;name&apos;</font>: <font color="#A6E22E">&apos;Portal Gun&apos;</font><b>}</b>,
        <b>{</b><font color="#A6E22E">&apos;name&apos;</font>: <font color="#A6E22E">&apos;Plumbus&apos;</font><b>}</b>
    <b>]</b>,
    <font color="#A6E22E">&apos;active&apos;</font>: <font color="#A6E22E"><i>True</i></font>,
    <font color="#A6E22E">&apos;affiliation&apos;</font>: <font color="#AE81FF"><i>None</i></font>
<b>}</b>

Rich 标记

Rich 还支持 自定义标记语法 来设置颜色和样式,例如

import typer
from rich import print


def main():
    print("[bold red]Alert![/bold red] [green]Portal gun[/green] shooting! :boom:")


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

<font color="#F92672"><b>Alert!</b></font> <font color="#A6E22E">Portal gun</font> shooting! 💥

在这个示例中,您可以看到如何使用字体样式、颜色,甚至表情符号。

要了解更多信息,请查看 Rich 文档

Rich 表格

Rich 在内部的工作方式是使用 Console 对象来显示信息。

当您调用 Rich 的 print 时,它会自动创建此对象并使用它。

但是对于高级用例,您可以自己创建一个 Console

import typer
from rich.console import Console
from rich.table import Table

console = Console()


def main():
    table = Table("Name", "Item")
    table.add_row("Rick", "Portal Gun")
    table.add_row("Morty", "Plumbus")
    console.print(table)


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

在此示例中,我们创建了一个 Console 和一个 Table。然后我们可以向表格中添加一些行,并打印它。

如果您运行它,您将看到一个格式良好的表格

$ python main.py

┏━━━━━━━┳━━━━━━━━━━━━┓
┃<b> Name  </b>┃<b> Item       </b>┃
┡━━━━━━━╇━━━━━━━━━━━━┩
│ Rick  │ Portal Gun │
│ Morty │ Plumbus    │
└───────┴────────────┘

Rich 还有许多其他功能,例如,您可以查看以下文档

Typer 和 Rich

如果您想知道应该使用什么工具,Typer 对于构建命令行应用程序很有用,它具有选项、参数、子命令、数据验证等功能。

通常,Typer 往往是程序的入口点,从用户那里获取第一个输入。

Rich 对于需要显示信息的部件很有用。在屏幕上显示漂亮的内容。

TyperRich 相结合,可以为您的命令行应用程序实现最佳效果。

“标准输出”和“标准错误”

打印工作的底层方式是操作系统(Linux、Windows、macOS)将我们打印的内容视为我们的 CLI 程序正在向一个名为“标准输出”的“虚拟文件写入文本

当我们的代码“打印”内容时,它实际上是“写入”到“标准输出”的这个“虚拟文件”中。

这可能看起来很奇怪,但这就是 CLI 程序和操作系统相互交互的方式。

然后操作系统在屏幕上显示我们的 CLI 程序“写入”到名为“标准输出”的“虚拟文件”中的任何内容。

标准错误

还有一个名为“标准错误”的“虚拟文件”,通常仅用于错误。

但我们也可以“打印”到“标准错误”。这两个都会在终端上显示给用户。

信息

如果您使用 PowerShell,您打印到“标准错误”的内容很可能不会显示在终端中。

在 PowerShell 中,要查看“标准错误”,您必须检查变量 $Error

但在 Bash、Zsh 和 Fish 中,它会正常工作。

打印到“标准错误”

您可以通过使用 stderr=True 创建一个 Rich Console 来打印到“标准错误”。

提示

stderr 是“标准错误”的缩写。

使用 stderr=True 告诉Rich,输出应显示在“标准错误”中。

import typer
from rich.console import Console

err_console = Console(stderr=True)


def main():
    err_console.print("Here is something written to standard error")


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

当您在终端中尝试它时,它可能看起来完全一样

$ python main.py

Here is something written to standard error

“标准输入”

最后,当您在键盘中键入文本到终端时,操作系统也会将其视为另一个“虚拟文件”,您正在向其写入文本。

此虚拟文件称为“标准输入”。

这有什么用

现在这可能看起来毫无用处 🤷‍♂。

但理解这一点在未来会派上用场,例如用于自动完成和测试。

Typer Echo

警告

在大多数情况下,建议使用 Rich 来显示高级信息。

您可能可以跳过本节的其余部分。🎉😎

Typer 还具有一个小实用程序 typer.echo(),用于在屏幕上打印信息,它直接来自 Click。但通常您不需要它。

对于最简单的情况,您可以使用标准 Python print()

对于您希望以更美观或更高级的内容显示数据的情况,您应该使用 Rich

为什么是 typer.echo

typer.echo()(实际上只是 click.echo())应用一些检查来尝试将二进制数据转换为字符串,以及其他类似操作。

但在大多数情况下,您不需要它,因为在现代 Python 字符串(str)中已经支持并使用 Unicode,并且您很少会处理您想要在屏幕上打印的纯 bytes

如果您有一些 bytes 对象,您可能希望在尝试打印它们之前有意直接解码它们。

如果您想使用颜色和其他功能打印数据,那么您最好使用 Rich 中更高级的工具。

信息

typer.echo() 直接来自 Click,您可以在 Click 文档 中阅读更多相关信息。

颜色

技术细节

颜色在终端中工作的原理是使用一些代码(ANSI 转义序列)作为文本的一部分。

因此,有色文本仍然只是一个 str

提示

同样,您最好使用 Rich 来实现此目的。😎

您可以使用 typer.style() 创建有色字符串以输出到终端,它会为您提供 str,然后您可以将其传递给 typer.echo()

import typer


def main(good: bool = True):
    message_start = "everything is "
    if good:
        ending = typer.style("good", fg=typer.colors.GREEN, bold=True)
    else:
        ending = typer.style("bad", fg=typer.colors.WHITE, bg=typer.colors.RED)
    message = message_start + ending
    typer.echo(message)


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

提示

参数 fgbg 接收带有颜色名称的字符串,用于“foreground”和“background”颜色。您可以简单地传递 fg="green"bg="red"

但是 Typer 将它们全部作为变量提供,例如 typer.colors.GREEN,这样您就可以在选择它们时使用自动完成。

检查一下

python main.py 一切 正常 python main.py --no-good 一切 异常

您可以将这些函数参数传递给 typer.style()

  • fg:前景色。
  • bg:背景色。
  • bold:启用或禁用粗体模式。
  • dim:启用或禁用暗淡模式。此模式支持不佳。
  • underline:启用或禁用下划线。
  • blink:启用或禁用闪烁。
  • reverse:启用或禁用反向渲染(前景色变为背景色,反之亦然)。
  • reset:默认情况下,在字符串的末尾添加一个重置所有代码,这意味着样式不会继承。可以禁用此功能以组合样式。

信息

您可以在 Click 关于 style() 的文档 中阅读更多相关信息。

typer.secho() - 样式和打印

提示

如果您没有看到上面,您最好使用 Rich 来实现此目的。😎

有一个更短的格式可以同时使用 typer.secho() 进行样式和打印,它类似于 typer.echo(),但还添加了类似于 typer.style() 的样式

import typer


def main(name: str):
    typer.secho(f"Welcome here {name}", fg=typer.colors.MAGENTA)


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

检查一下

python main.py Camila 欢迎来到这里,Camila