pprint 是 Python 标准库中的模块,全称 “pretty print”,用于格式化输出复杂的数据结构(如字典、列表、嵌套对象),使其更易读。与内置的 print 函数相比,pprint 提供更好的排版,自动添加换行和缩进,尤其适合调试或展示嵌套数据结构。pprint 模块简单易用,广泛用于开发、数据分析和日志记录。

以下是对 pprint 库的详细介绍,包括其功能、用法和实际应用。


1. pprint 库的作用

  • 格式化输出:以人类可读的方式打印复杂数据结构(如嵌套字典、列表)。
  • 自动缩进:为嵌套层级添加适当的缩进和换行。
  • 控制输出:支持自定义宽度、深度、排序等选项。
  • 调试友好:清晰展示数据结构,便于检查内容。
  • 标准库内置:无需额外安装,适合任何 Python 项目。

2. 安装与环境要求

  • Python 版本:内置于 Python 标准库(Python 2.x 和 3.x 均支持)。
  • 依赖:无外部依赖。
  • 导入方式:
    from pprint import pprint
    
  • 验证可用性:
    import pprint
    print(pprint.__name__)  # 输出: pprint
    

3. 核心功能与用法

pprint 模块的核心是通过 pprint() 函数或 PrettyPrinter 类格式化输出数据。以下是主要功能和示例。

3.1 基本使用(pprint 函数)

使用 pprint() 格式化打印数据结构。

from pprint import pprint

data = {
    "name": "Alice",
    "age": 30,
    "hobbies": ["reading", "gaming"],
    "address": {
        "street": "123 Main St",
        "city": "Wonderland",
        "coords": {"lat": 40.7128, "lon": -74.0060}
    }
}

# 普通 print
print(data)

# 使用 pprint
pprint(data)

输出对比:

  • print 输出(单行,难以阅读):
    {'name': 'Alice', 'age': 30, 'hobbies': ['reading', 'gaming'], 'address': {'street': '123 Main St', 'city': 'Wonderland', 'coords': {'lat': 40.7128, 'lon': -74.0060}}}
    
  • pprint 输出(格式化,易读):
    {'address': {'city': 'Wonderland',
                 'coords': {'lat': 40.7128, 'lon': -74.006},
                 'street': '123 Main St'},
     'age': 30,
     'hobbies': ['reading', 'gaming'],
     'name': 'Alice'}
    

说明:

  • pprint 自动为嵌套结构添加换行和缩进。
  • 默认宽度为 80 字符,自动折行。
3.2 控制输出格式

pprint() 支持多个参数自定义输出。

from pprint import pprint

data = {"a": [1, 2, 3], "b": {"x": 10, "y": 20}, "c": "text"}

# 自定义宽度和缩进
pprint(data, width=50, indent=2)

# 限制嵌套深度
pprint(data, depth=1)

# 排序字典键
pprint(data, sort_dicts=True)

输出示例:

  • width=50, indent=2:
    {  'a': [1, 2, 3],
      'b': {'x': 10, 'y': 20},
      'c': 'text'}
    
  • depth=1:
    {'a': [...], 'b': {...}, 'c': 'text'}
    
  • sort_dicts=True:
    {'a': [1, 2, 3], 'b': {'x': 10, 'y': 20}, 'c': 'text'}
    

说明:

  • width:控制每行最大字符数。
  • indent:设置缩进空格数。
  • depth:限制显示的嵌套层级,超出部分显示为 ...。
  • sort_dicts(Python 3.8+):是否按键排序字典(默认 False)。
3.3 PrettyPrinter 类

使用 PrettyPrinter 类创建自定义打印器,复用配置。

from pprint import PrettyPrinter

# 创建自定义打印器
pp = PrettyPrinter(width=40, indent=2, sort_dicts=True)

data = {"a": [1, 2, 3], "b": {"x": 10, "y": 20}, "c": "text"}
pp.pprint(data)

输出示例:

{  'a': [1, 2, 3],
  'b': {  'x': 10,
         'y': 20},
  'c': 'text'}

说明:

  • PrettyPrinter 适合需要一致格式的场景。
  • 支持与 pprint() 相同的参数。
3.4 格式化为字符串

使用 pformat 返回格式化字符串,而不是直接打印。

from pprint import pformat

data = {"a": [1, 2, 3], "b": {"x": 10, "y": 20}}
formatted = pformat(data, width=50)
print(f"Formatted data:\n{formatted}")

输出示例:

Formatted data:
{'a': [1, 2, 3], 'b': {'x': 10, 'y': 20}}

说明:

  • pformat 返回字符串,适合日志记录或进一步处理。
  • 支持与 pprint 相同的参数。
3.5 处理自定义对象

pprint 默认格式化内置类型,自定义对象需实现 __repr__。

from pprint import pprint

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __repr__(self):
        return f"Person(name={self.name!r}, age={self.age})"

data = [Person("Alice", 30), Person("Bob", 25)]
pprint(data)

输出示例:

[Person(name='Alice', age=30),
 Person(name='Bob', age=25)]

说明:

  • 自定义 __repr__ 控制对象在 pprint 中的显示。
  • 避免使用 __str__,因为 pprint 优先调用 __repr__。
3.6 流控制

将输出写入文件或自定义流。

from pprint import pprint
import sys

data = {"a": [1, 2, 3], "b": {"x": 10, "y": 20}}

# 输出到文件
with open("output.txt", "w") as f:
    pprint(data, stream=f)

# 输出到标准错误
pprint(data, stream=sys.stderr)

说明:

  • stream 参数指定输出目标(如文件或 sys.stderr)。
  • 默认 stream=None,输出到 sys.stdout。

4. 性能与特点

  • 高效性:对中小型数据结构,格式化速度快。
  • 易用性:无需配置,开箱即用。
  • 灵活性:支持宽度、深度、缩进等自定义选项。
  • 局限性:
    • 超大数据结构(数千嵌套层级)可能导致性能下降。
    • 不支持颜色高亮或复杂格式化(如 JSON 着色)。
  • 跨版本兼容:
    • Python 2.x 和 3.x 均支持,3.8+ 增加 sort_dicts 参数。
    • 标准库,无兼容性问题。

5. 实际应用场景

  • 调试:打印复杂数据结构(如 API 响应、配置字典)。
  • 数据分析:格式化 Pandas DataFrame 或 NumPy 数组。
  • 日志记录:使用 pformat 将数据结构写入日志。
  • API 开发:展示 JSON 响应或请求体。
  • 教学与文档:生成易读的输出,用于演示或说明。

示例(与 FastAPI 集成):

from fastapi import FastAPI
from pprint import pformat
from loguru import logger

app = FastAPI()

@app.get("/data")
async def get_data():
    data = {
        "users": [
            {"id": 1, "name": "Alice", "roles": ["admin", "user"]},
            {"id": 2, "name": "Bob", "roles": ["user"]}
        ],
        "settings": {"debug": True, "version": "1.0"}
    }
    # 记录格式化数据
    logger.info(f"Response data:\n{pformat(data)}")
    return data

输出示例(日志):

2025-05-09 12:34:56.123 | INFO     | Response data:
{'settings': {'debug': True, 'version': '1.0'},
 'users': [{'id': 1, 'name': 'Alice', 'roles': ['admin', 'user']},
           {'id': 2, 'name': 'Bob', 'roles': ['user']}]}

说明:

  • 使用 pformat 记录 API 响应,便于调试。

6. 与替代方案对比

  • print:
    • 简单,但输出单行,复杂结构难以阅读。
    • 无格式化选项。
  • json.dumps:
    import json
    print(json.dumps(data, indent=2))
    
    • 适合 JSON 数据,提供缩进,但不支持非 JSON 序列化对象(如自定义类)。
    • 输出格式固定,缺少 pprint 的深度控制。
  • yaml.dump:
    import yaml
    print(yaml.dump(data))
    
    • 生成 YAML 格式,适合配置文件,但依赖外部库。
  • pprint 的优势:
    • 内置标准库,无需额外安装。
    • 灵活控制输出(宽度、深度、排序)。
    • 支持任意 Python 对象(通过 __repr__)。

7. 注意事项

  • 性能:
    • 超大数据结构可能导致格式化缓慢,建议限制 depth:
      pprint(large_data, depth=2)
      
    • 对于简单数据,print 可能更快。
  • 输出控制:
    • 默认宽度 80 字符,可能导致意外折行,调整 width:
      pprint(data, width=120)
      
    • 深度限制(depth)适合快速预览复杂对象。
  • 自定义对象:
    • 确保自定义类实现 __repr__,否则输出可能是 <Object at 0x...>。
  • Python 版本:
    • Python 3.8+ 支持 sort_dicts,旧版本字典顺序随机。
    • Python 2.x 的 pprint 功能略少,但基本兼容。
  • 替代工具:
    • 对于 JSON 数据,json.dumps(indent=2) 更轻量。
    • 对于彩色输出,结合 rich 库:
      from rich import print as rprint
      rprint(data)
      

8. 综合示例

以下是一个综合示例,展示 pprint 在调试、日志记录和自定义对象中的使用:

from pprint import pprint, pformat, PrettyPrinter
from loguru import logger
import sys

# 自定义类
class Employee:
    def __init__(self, name, id, skills):
        self.name = name
        self.id = id
        self.skills = skills
    
    def __repr__(self):
        return f"Employee(name={self.name!r}, id={self.id}, skills={self.skills!r})"

# 示例数据
data = {
    "company": "Tech Corp",
    "employees": [
        Employee("Alice", 1, ["Python", "SQL"]),
        Employee("Bob", 2, ["Java", "Docker"]),
    ],
    "projects": {
        "AI": {"status": "active", "budget": 100000},
        "Web": {"status": "planning", "budget": 50000}
    }
}

# 基本打印
print("Basic pprint:")
pprint(data, width=60)

# 自定义打印器
print("\nCustom PrettyPrinter:")
pp = PrettyPrinter(width=50, indent=2, depth=2, stream=sys.stderr)
pp.pprint(data)

# 格式化为字符串并记录
logger.add("app.log", format="{time} | {level} | {message}")
logger.info("Data structure:\n{}", pformat(data, width=70))

# 限制深度
print("\nDepth-limited output:")
pprint(data, depth=1)

输出示例:

  • 终端(pprint):
    Basic pprint:
    {'company': 'Tech Corp',
     'employees': [Employee(name='Alice', id=1, skills=['Python', 'SQL']),
                   Employee(name='Bob', id=2, skills=['Java', 'Docker'])],
     'projects': {'AI': {'budget': 100000, 'status': 'active'},
                  'Web': {'budget': 50000, 'status': 'planning'}}}
    
    Custom PrettyPrinter:
    {  'company': 'Tech Corp',
      'employees': [...],
      'projects': {...}}
    
    Depth-limited output:
    {'company': 'Tech Corp', 'employees': [...], 'projects': {...}}
    
  • 日志(app.log):
    2025-05-09T12:34:56.123456 | INFO     | Data structure:
    {'company': 'Tech Corp',
     'employees': [Employee(name='Alice', id=1, skills=['Python', 'SQL']),
                   Employee(name='Bob', id=2, skills=['Java', 'Docker'])],
     'projects': {'AI': {'budget': 100000, 'status': 'active'},
                  'Web': {'budget': 50000, 'status': 'planning'}}}
    

说明:

  • 展示不同宽度和深度的格式化输出。
  • 使用 PrettyPrinter 输出到 sys.stderr。
  • 通过 pformat 记录日志。
  • 自定义 Employee 类的 __repr__ 确保清晰输出。

9. 资源与文档

更多推荐