Rich:让 Python 终端输出不再单调

本文介绍 Rich 这个强大的 Python 终端美化库,展示如何在终端中实现丰富的格式、颜色、表格、进度条,以及渲染 Markdown 和语法高亮代码,让终端输出不再单调。

前言

你是否厌倦了单调的黑底白字终端输出?是否希望在终端中也能有丰富的格式、颜色、表格、进度条,甚至能渲染 Markdown 和语法高亮代码?

Rich 就是为此而生的 Python 库——它让你的终端输出不再单调,而是变得丰富多彩、美观易读

本文将深入介绍 Rich 这个强大的 Python 终端美化库,展示它如何让你的 CLI 工具和脚本变得专业且引人入胜。


什么是 Rich?

核心理念

Rich 是一个 Python 库,用于在终端中实现富文本和美观的格式化。它的设计目标是:

  • 开箱即用:API 简洁,易于上手
  • 功能丰富:表格、进度条、Markdown、语法高亮等开箱即用
  • 跨平台兼容:支持 Linux、macOS 和 Windows
  • Jupyter 友好:无需额外配置即可在 Jupyter 中使用

项目信息

属性 信息
作者 Will McGugan (@willmcgugan)
GitHub Textualize/rich
PyPI rich
文档 Read the Docs
姊妹项目 Textual - 终端 UI 框架
Python 版本 3.8+
许可证 MIT

安装

使用 pip 安装:

1
pip install rich

安装后,运行以下命令测试 Rich 输出:

1
python -m rich

你将看到 Rich 的各种功能演示!


快速开始

1. Rich Print

Rich 提供了 print() 方法,签名与 Python 内置 print() 完全相同,但支持丰富的格式化:

1
2
3
from rich import print

print("Hello, [bold magenta]World[/bold magenta]!", ":vampire:", locals())

输出(带颜色和 emoji):

1
Hello, World! 🧛

2. Rich REPL

在 Python REPL 中安装 Rich 后,所有数据结构都会被美观地打印和高亮:

1
2
>>> from rich import pretty
>>> pretty.install()

现在在 REPL 中输入任何对象,Rich 都会自动美化显示。

3. 使用 Console 对象

对于更精细的控制,使用 Console 对象:

1
2
3
4
from rich.console import Console

console = Console()
console.print("Hello", "World!")

添加样式

1
2
3
4
5
6
7
# 整行样式
console.print("Hello", "World!", style="bold red")

# 使用 markup(类似 BBCode)
console.print(
"Where there is a [bold cyan]Will[/bold cyan] there [u]is[/u] a [i]way[/i]."
)

Rich Markup 语法

1
2
3
4
5
[bold]加粗[/bold]
[italic]斜体[/italic]
[underline]下划线[/underline]
[red]红色[/red]
[bold magenta]粗体洋红[/bold magenta]


核心功能

1. 美化日志:log()

Console.log() 方法类似于 print(),但显示时间、文件和行号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from rich.console import Console

console = Console()

test_data = [
{"jsonrpc": "2.0", "method": "sum", "params": [1, 2, 4], "id": "1"},
{"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
]

def test_log():
enabled = False
context = {"foo": "bar"}
movies = ["Deadpool", "Rise of Skywalker"]
console.log("Hello from", console, "!")
console.log(test_data, log_locals=True)

test_log()

输出(带时间戳、文件名、行号和本地变量表):

1
2
3
4
5
6
7
8
9
10
11
12
13
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ test.py ┃
┃ test_log ┃
┃ 12:00:00 ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
┃ Hello from <Console id=0x... │
┃ {'jsonrpc': '2.0', 'method': 'sum', ...} │
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
┃ locals() │
┃ enabled = False │
┃ context = {'foo': 'bar'} │
┃ movies = ['Deadpool', 'Rise of Skywalker']│
└─────────────────────────────────────────────────────────────────────────────────

Logging Handler

Rich 提供与 Python logging 模块兼容的 Handler:

1
2
3
4
5
6
7
8
9
10
11
import logging
from rich.logging import RichHandler

logging.basicConfig(
level="NOTSET",
format="%(message)s",
handlers=[RichHandler()]
)

logger = logging.getLogger(__name__)
logger.info("Hello, Rich!")

2. 表格渲染

Rich 可以渲染美观的 Unicode 表格:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from rich.console import Console
from rich.table import Table

console = Console()

table = Table(show_header=True, header_style="bold magenta")

table.add_column("Date", style="dim", width=12)
table.add_column("Title")
table.add_column("Production Budget", justify="right")
table.add_column("Box Office", justify="right")

table.add_row(
"Dec 20, 2019",
"Star Wars: The Rise of Skywalker",
"$275,000,000",
"$375,126,118"
)

table.add_row(
"May 25, 2018",
"[red]Solo[/red]: A Star Wars Story",
"$275,000,000",
"$393,151,347"
)

console.print(table)

输出(带 Unicode 边框和对齐):

1
2
3
4
5
6
╭────────────────────────────────────────────────────────────────────────────╮
│ Date │ Title │ Production Budget │ Box Office │
├────────────────────────────────────────────────────────────────────────────┤
│ Dec 20, 2019 │ Star Wars: The Rise of Skywalker │ $275,000,000 │ $375,126,118 │
│ May 25, 2018 │ Solo: A Star Wars Story │ $275,000,000 │ $393,151,347 │
╰────────────────────────────────────────────────────────────────────────────╯

3. 进度条

Rich 可以渲染无闪烁的多进度条:

1
2
3
4
from rich.progress import track

for step in track(range(100), description="Processing..."):
do_step(step)

输出

1
Processing... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 45/100 45%

多个进度条

1
2
3
4
5
6
7
8
9
10
11
from rich.progress import Progress

with Progress() as progress:
task1 = progress.add_task("[red]Downloading...", total=100)
task2 = progress.add_task("[green]Processing...", total=100)
task3 = progress.add_task("[cyan]Uploading...", total=100)

while not progress.finished:
progress.update(task1, advance=0.1)
progress.update(task2, advance=0.2)
progress.update(task3, advance=0.15)

显示详细信息

1
2
3
4
5
6
7
8
9
10
from rich.progress import track, BarColumn, TextColumn, TimeRemainingColumn

for step in track(
range(100),
description="Downloading",
console=console,
show_speed=True,
show_eta=True
):
process_step(step)

4. 状态指示器(Spinner)

对于难以计算进度的任务,使用 status() 显示动画:

1
2
3
4
5
6
7
8
9
10
11
from time import sleep
from rich.console import Console

console = Console()

with console.status("[bold green]Working on tasks...") as status:
tasks = [f"task {n}" for n in range(1, 11)]
while tasks:
task = tasks.pop(0)
sleep(0.5)
console.log(f"{task} complete")

查看所有可用的 spinner

1
python -m rich.spinner

5. Emoji 支持

在终端输出中使用 emoji(名称在两个冒号之间):

1
2
3
4
from rich.console import Console

console = Console()
console.print(":smiley: :vampire: :pile_of_poo: :thumbs_up: :raccoon:")

输出

1
😃 🧛 💩 👍 🦝

6. 树形结构渲染

1
2
3
4
5
6
7
8
9
10
11
from rich.tree import Tree
from rich.console import Console

console = Console()

tree = Tree("📁 project")
tree.add("📁 src").add("📄 main.py")
tree.add("📁 tests")
tree.add("📄 README.md")

console.print(tree)

输出

1
2
3
4
5
📁 project
├─ 📁 src
│ └─ 📄 main.py
├─ 📁 tests
└─ 📄 README.md

7. 多列布局

1
2
3
4
5
6
7
8
import os
from rich.console import Console
from rich.columns import Columns

console = Console()

directory = os.listdir(".")
console.print(Columns(directory))

8. Markdown 渲染

1
2
3
4
5
6
7
8
from rich.console import Console
from rich.markdown import Markdown

console = Console()

with open("README.md") as readme:
markdown = Markdown(readme.read())
console.print(markdown)

Rich 会将 Markdown 格式转换为终端友好的输出。

9. 语法高亮

1
2
3
4
5
6
7
8
9
10
11
12
from rich.console import Console
from rich.syntax import Syntax

console = Console()

my_code = '''
def hello_world():
print("Hello, World!")
'''

syntax = Syntax(my_code, "python", theme="monokai", line_numbers=True)
console.print(syntax)

输出(带语法高亮和行号):

1
2
1 │ def hello_world():
2 │ print("Hello, World!")

支持的语言:Python, JavaScript, HTML, CSS, JSON, YAML 等(基于 Pygments)

10. 美化异常(Tracebacks)

设置 Rich 为默认异常处理器:

1
2
3
from rich.traceback import install

install(show_locals=True)

现在任何未捕获的异常都会被美观地显示,包括:

  • 彩色语法高亮
  • 清晰的堆栈跟踪
  • 局部变量值(show_locals=True

输出示例

1
2
3
4
5
6
7
8
9
10
11
12
Traceback (most recent call last):
File "test.py", line 12, in <module>
do_something()
File "test.py", line 8, in do_something
result = divide(10, 0)
ZeroDivisionError: division by zero

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ locals() │
┃ x = 10 │
┃ result = None │
└─────────────────────────────────────────────────────────────────────────────────

11. Inspect 功能

生成任何 Python 对象的详细报告:

1
2
3
4
from rich import inspect

my_list = ["foo", "bar"]
inspect(my_list, methods=True)

实际应用场景

场景 1:CLI 数据导出工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from rich.console import Console
from rich.table import Table
from rich.progress import track
import json

console = Console()

def export_data(data, filename):
with console.status(f"[bold green]Exporting to {filename}...") as status:
table = Table(title="Export Summary")
table.add_column("Metric")
table.add_column("Value", justify="right")

for key, value in data.items():
table.add_row(key, str(value))

console.print(table)

# 导出到文件
with open(filename, "w") as f:
json.dump(data, f, indent=2)

status.update(f"[green]Done! {len(data)} records exported")

# 使用
export_data({"users": 1000, "posts": 5000}, "export.json")

场景 2:长时间运行的服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import logging
from rich.logging import RichHandler

logging.basicConfig(
level="INFO",
format="%(message)s",
datefmt="[%X]",
handlers=[RichHandler(rich_tracebacks=True, tracebacks_show_locals=True)]
)

logger = logging.getLogger(__name__)

class Server:
def start(self):
logger.info("Server starting...")

while True:
try:
self.handle_request()
except Exception as e:
logger.exception(f"Request failed: {e}")

def handle_request(self):
logger.debug("Processing request...")
# 处理逻辑
logger.info("Request completed successfully")

server = Server()
server.start()

场景 3:数据科学可视化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from rich.console import Console
from rich.table import Table
from rich.columns import Columns
from rich.panel import Panel

console = Console()

def show_metrics(metrics):
# 创建表格
table = Table(show_header=True)
table.add_column("Metric", style="cyan")
table.add_column("Value", style="green")

for key, value in metrics.items():
table.add_row(key, f"{value:.2f}")

# 创建面板
panel = Panel(table, title="[bold]Metrics Dashboard", border_style="blue")
console.print(panel)

# 使用
metrics = {
"Accuracy": 0.95,
"Precision": 0.92,
"Recall": 0.89,
"F1 Score": 0.90
}
show_metrics(metrics)

场景 4:下载器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import requests
from rich.progress import Progress, BarColumn, TextColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
from rich.console import Console

console = Console()

def download_file(url, filename):
response = requests.get(url, stream=True)
total_size = int(response.headers.get('content-length', 0))

with Progress(
TextColumn("[bold blue]{task.description}"),
BarColumn(bar_width=None),
DownloadColumn(),
TransferSpeedColumn(),
TimeRemainingColumn(),
) as progress:
task = progress.add_task(f"Downloading {filename}", total=total_size)

with open(filename, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
progress.update(task, advance=len(chunk))

console.print(f"[green]✓[/green] Downloaded {filename}")

# 使用
download_file(
"https://example.com/large-file.zip",
"large-file.zip"
)

高级技巧

1. 自定义 Console

1
2
3
4
5
6
7
8
9
10
11
12
13
from rich.console import Console
from rich.theme import Theme

custom_theme = Theme({
"info": "dim cyan",
"warning": "magenta",
"error": "bold red"
})

console = Console(theme=custom_theme)
console.print("[info]This is an info message")
console.print("[warning]This is a warning")
console.print("[error]This is an error")

2. 永久更改样式

1
2
3
4
5
6
7
8
9
10
11
from rich.console import Console

console = Console()

# 获取上下文管理器
with console.capture():
console.print("This won't be displayed")
output = console.get()

# 修改后输出
console.print(f"Captured: {output}")

3. 布局控制

1
2
3
4
5
6
7
8
9
10
11
12
13
from rich.console import Console
from rich.layout import Layout
from rich.panel import Panel

console = Console()

layout = Layout()

layout["header"].update(Panel("My App", style="bold blue"))
layout["body"].update("Content goes here")
layout["footer"].update("Status: Ready")

console.print(layout)

4. 分组和规则

1
2
3
4
5
6
7
8
9
from rich.console import Console
from rich.rule import Rule

console = Console()

console.print(Rule("[bold red]Section 1", style="red"))
console.print("Content of section 1")
console.print(Rule("[bold green]Section 2", style="green"))
console.print("Content of section 2")

兼容性

平台支持

平台 支持状态 备注
Linux ✅ 完全支持 真彩色和 emoji 完全支持
macOS ✅ 完全支持 真彩色和 emoji 完全支持
Windows ✅ 支持 新终端(Windows Terminal)完全支持;经典终端限制 16 色
Jupyter Notebook ✅ 无需配置 开箱即用

Python 版本

  • 最低要求:Python 3.8+
  • 推荐:Python 3.10+

最佳实践

1. 性能考虑

1
2
3
4
5
6
7
8
9
# ❌ 避免:在循环中创建新的 Console
for item in items:
console = Console() # 每次创建新对象
console.print(item)

# ✅ 推荐:重用 Console 对象
console = Console()
for item in items:
console.print(item)

2. 日志级别选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import logging
from rich.logging import RichHandler

# 开发环境:详细日志
if development:
logging.basicConfig(
level="DEBUG",
handlers=[RichHandler()]
)
# 生产环境:仅重要信息
else:
logging.basicConfig(
level="WARNING",
handlers=[RichHandler()]
)

3. 错误处理

1
2
3
4
5
6
7
8
from rich.traceback import install

# 开发环境:显示局部变量
if development:
install(show_locals=True)
# 生产环境:不显示局部变量(安全)
else:
install(show_locals=False)

4. 颜色使用原则

1
2
3
4
5
6
7
# ✅ 好的:语义化使用颜色
console.print("[green]Success![/green] Task completed")
console.print("[yellow]Warning:[/yellow] Low disk space")
console.print("[red]Error:[/red] Failed to connect")

# ❌ 避免:过度使用颜色
console.print("[bold red][underline][italic]ERROR!!![/italic][/underline][/bold]")

与其他工具对比

特性 Rich Colorama Termcolor
表格渲染
进度条
Markdown 渲染
语法高亮
Tree 结构
Traceback 美化
跨平台 ⚠️
简单性 简单 简单 简单

常见问题

Q1: Rich 会影响性能吗?

影响很小。Rich 在大多数情况下对性能的影响可以忽略不计,但有一些优化建议:

  • 重用 Console 对象而不是重复创建
  • 在生产环境中禁用不必要的特性(如 show_locals
  • 对于大量输出,考虑禁用某些样式

Q2: Rich 可以在 Windows 上使用吗?

可以。Rich 完全支持 Windows:

  • 新终端(Windows Terminal):真彩色和 emoji 完全支持
  • 经典终端:限制 16 种颜色
  • CMD:部分支持(建议使用 Windows Terminal 或第三方终端)

Q3: Rich 和 Textual 有什么区别?

Rich:专注于输出美化(表格、进度条、语法高亮等)

Textual:Rich 的姊妹项目,专注于构建完整的终端 UI 应用(TUI),类似 curses 但更现代化。

Q4: 如何在 Jupyter 中使用 Rich?

无需任何配置!Rich 自动检测 Jupyter 环境,并使用 HTML/JS 渲染而不是 ANSI 代码。

1
2
3
4
# 在 Jupyter 中
from rich import print

print("Hello, [bold]Jupyter![/bold]")

Q5: Rich 支持哪些颜色主题?

Rich 使用 Pygments 进行语法高亮,支持所有 Pygments 主题:

  • monokai
  • github-dark
  • solarized-dark
  • nord
  • dracula
  • 等等…

查看所有主题:

1
python -c "from pygments.styles import get_all_styles; print([s.name for s in get_all_styles()])"


总结

Rich 是一个让 Python 终端输出变得美观、专业且功能丰富的强大工具。

核心优势

  1. 简单易用:API 直观,开箱即用
  2. 功能强大:表格、进度条、Markdown、语法高亮等
  3. 跨平台:支持 Linux、macOS、Windows 和 Jupyter
  4. 美观输出:Unicode 支持、真彩色、emoji
  5. 生产就绪:与 logging 模块集成、可配置

适用场景

  • ✅ CLI 工具开发
  • ✅ 长时间运行的服务
  • ✅ 数据科学可视化
  • ✅ 脚本和自动化工具
  • ✅ 调试和日志记录
  • ✅ 下载器和数据处理工具

资源链接


如果你还在使用单调的终端输出,试试 Rich 吧——它会让你的 Python 终端体验焕然一新! 🎨