Python列表打印进阶:从print到pprint与json的实战指南
你在调试 Python 程序时是不是经常直接写一句print(my_list)来看数据数据量小的时候还能忍一旦列表里有几十个元素、嵌套几层结构输出就会挤成密密麻麻的一行。中文乱码、换行丢失、类型显示不清楚、日志里内容被截断这些问题几乎每个人都遇到过。列表打印看似只是print的基础用法但在真实项目里它牵扯到三个层次的问题第一层是“能不能把整个列表显示出来”第二层是“能不能按可读的格式显示出来”第三层是“显示结果是否便于日志分析、接口排错和数据核对”。很多时候线上问题排查效率低不是算法复杂而是最基础的数据打印方式没选对。这篇文章会从 Python 中列表打印的基础写法讲起逐步深入到格式化输出、嵌套结构处理、日志场景下的打印策略并给出一套在实际开发中可以直接复制使用的做法。读完你会有一个明确判断什么时候直接print(list)就够了什么时候必须换成循环、join()、pprint或 JSON 序列化。1. 这篇文章真正要解决的问题先看一个很常见的场景。你从数据库查出 10 条用户记录每条记录是一个字典放进一个列表里然后直接print(users)。控制台输出的结果可能是这样的[{name: 张三, age: 28, city: 北京}, {name: 李四, age: 32, city: 上海}, {name: 王五, age: 24, city: 广州}]这条输出有几个问题。第一阅读困难。所有记录挤在同一行字段和记录之间的边界不清晰。如果列表里有 100 条记录控制台会横向滚动或自动换行你很难快速找到“李四”的数据。第二中文显示可能异常。在某些终端或日志系统中直接输出中文会变成\u5f20\u4e09这种转义序列看起来像乱码实际上是因为默认的repr()策略把非 ASCII 字符转义了。第三深层嵌套结构完全不可读。如果列表里的元素是字典字典里又有列表列表里又有字典那么直接print()输出的结果基本只能用来“确认程序没报错”无法用来核对逻辑。第四日志场景下信息不完整。使用logging模块时如果直接把大列表塞进日志消息日志系统会按整条消息处理。你无法控制缩进、无法分条记录后期用日志平台检索时也只能搜到一整块字符串。这篇文章要解决的问题就是围绕“Python 列表如何优雅、清晰、可控地输出”梳理出适合不同场景的打印方式。它不是一个复杂的算法问题但它直接影响开发调试效率、日志可读性和线上问题定位速度。凡是写过 Python 脚本处理数据、写接口返回列表、做数据处理任务的人都值得把这篇内容完整过一遍。2. 基础概念print、列表与可迭代对象在展开写法之前先把三个基本概念说清楚。很多初学者混淆它们导致选择错误的打印方式。2.1 print 到底做了什么print()是 Python 的内置函数。它的核心行为是把传入对象的“字符串表示形式”输出到标准输出流。这里有两个关键点第一print()不负责“转换数据格式”它只是调用对象的__str__()或__repr__()方法拿到字符串然后写到标准输出。第二多个参数传入时print()默认用空格分隔并在末尾追加换行符。这就是为什么print(item)在循环里会一行一个元素。看一个简单示例user {name: Alice, age: 30} print(user) # 实际调用的是 dict 的 __repr__() print(str(user)) # 显式转成字符串效果通常一样 print(repr(user)) # repr 与 str 在很多内置类型上结果相同对于列表、字典这类容器类型str()和repr()返回结果基本一致都是通过元素的repr()组合出来的。这意味着只要列表里的元素有自定义类打印效果就受该类的__repr__()方法影响。2.2 列表是容器不是普通字符串列表list是 Python 中最常用的可变序列类型。它可以存放任意类型的数据数字、字符串、字典、对象甚至可以嵌套列表。正因为它是“容器”直接打印容器时Python 需要把容器内部每个元素的字符串表示拼接出来。这个过程是递归的所以嵌套结构会变成一大串文本。容器打印的重点不是“输出”这个动作而是“如何控制容器内部元素的展示规则”。2.3 可迭代对象不等于列表在写打印逻辑时还会遇到一个容易混淆的概念可迭代对象。nums_range range(5) nums_list [0, 1, 2, 3, 4]直接print(nums_range)会输出range(0, 5)而不是元素内容。类似的情况还有生成器、迭代器、字典的键视图等。它们可以被for循环遍历但不一定实现了友好的__repr__()方法。处理它们时需要先用list()转换或者用循环逐个打印。下面的表格总结了不同容器的直接打印效果数据类型示例print()输出示例说明列表[1, 2, 3][1, 2, 3]直接输出方括号形式元组(1, 2, 3)(1, 2, 3)显示圆括号字典列表[{a: 1}][{a: 1}]单行内容多时难读rangerange(3)range(0, 3)不会展开成元素生成器(x for x in range(3))generator object ...不消耗则看不到元素集合{1, 2, 3}{1, 2, 3}无序每次输出顺序可能不同理解这些区别后你会发现“打印列表”不是在写一个简单语法而是在决定数据的展示形式和排查成本。3. 环境准备你需要什么本文的示例代码全部使用 Python 3 编写。实际开发中Python 3.8 以上版本都可以直接运行不需要额外安装第三方库。如果你的环境还没有准备好建议先检查版本python --versionWindows 下可能是py --version或python3 --version。只要输出是 Python 3.x 即可。部分示例会用到pprint和json它们都是 Python 标准库模块不需要 pip 安装。脚本保存为.py文件后在终端运行python demo_print_list.py如果你是初学者推荐用 IDE 或 VS Code 运行方便观察输出。如果只是在交互式环境里测试直接复制代码块即可。为了统一下文示例默认你在项目目录下创建脚本文件并运行。4. 基础打印方式拆解从最简单到最常用这一节我们从最简单的写法开始逐层深入。每种方式我都会说明它适合什么场景不适合什么场景。4.1 直接打印整个列表直接打印列表是 Python 学习过程中接触到的第一种方式# 文件路径demo/basic_direct.py fruits [apple, banana, cherry] print(fruits)运行结果[apple, banana, cherry]这种方式的优势是代码短、意图明确。调试时你先看一眼元素是否存在用它最方便。但它有几个明显局限一是列表元素数量大时所有内容会挤在同一行。在终端里超过宽度后显示会换行换行位置不可控阅读体验差。二是如果元素中包含自定义对象直接打印可能显示为__main__.Person object at 0x...完全没有业务信息。三是不利于日志检索。每一行日志是一个完整事件把几百个元素塞进一行会让日志平台难以对单个元素建立索引。所以直接print(list)只适合元素少、结构简单、纯调试的场景。4.2 使用 for 循环逐行打印当列表元素需要逐行展示时for循环是最直白的方案# 文件路径demo/basic_for_loop.py fruits [apple, banana, cherry] for fruit in fruits: print(fruit)运行结果apple banana cherry这个方式适合日志记录因为每行输出对应一个元素。你可以在循环内继续扩展例如加编号、加前缀、加判断条件。给元素加编号是常用需求可以用enumerate()# 文件路径demo/basic_enumerate.py fruits [apple, banana, cherry] for index, fruit in enumerate(fruits, start1): print(f{index}. {fruit})运行结果1. apple 2. banana 3. cherryfor 循环是处理列表打印时最可靠的基础设施。它的缺点是代码相对啰嗦如果只是要把元素用逗号拼成一行它就不是最优选择。4.3 使用 join() 拼接字符串列表如果列表里的元素全部是字符串并且你希望它们输出在同一行、用指定分隔符隔开join()是最优雅的方式# 文件路径demo/basic_join.py tags [python, list, print] line , .join(tags) print(line)运行结果python, list, printjoin()的原理是以调用它的字符串作为分隔符把传入的字符串可迭代对象拼接成一个新字符串。注意这里要求列表元素必须都是字符串。如果混入整数需要先转换# 文件路径demo/basic_join_mixed.py numbers [1, 2, 3] line , .join(str(num) for num in numbers) print(line)运行结果1, 2, 3这种写法的核心价值在于你完全控制分隔符、没有多余的方括号、没有字符串引号非常适合生成 CSV 一行、日志中的关键字段拼接、对外输出友好提示等场景。4.4 通过解包传递多个参数print()本身支持多个位置参数。你可以用解包操作符*把列表元素作为多个参数传入实现空格分隔的输出# 文件路径demo/basic_unpack.py nums [1, 2, 3] print(*nums)运行结果1 2 3这种方式适合快速查看一组数字。你还可以自定义sep参数print(*nums, sep-)运行结果1-2-3但这种写法有一个需要注意的坑如果列表有几千个元素*nums会展开成几千个位置参数虽然 Python 能接受但可读性和极端情况下的参数数量限制都需要考虑。这种写法更适合少量元素。4.5 小结基础方式如何选根据上面几种方式可以整理出简单的选择原则需求推荐方式理由快速确认列表内容直接print(list)代码最少每行一条数据for循环天然分行需要编号输出enumerate()同时拿到索引元素是字符串需要拼接join()分隔符可完全控制快速输出一组数字print(*list)简洁直观对于真实开发光会这些还不够。因为项目里最常见的列表不是基础类型列表而是字典列表下面单独展开。5. 复杂场景打印字典列表与嵌套结构5.1 直接打印字典列表的痛点假设接口返回的数据是列表列表中的每一项是一个用户字典# 文件路径demo/dict_list_direct.py users [ {name: 张三, age: 28, city: 北京}, {name: 李四, age: 32, city: 上海}, {name: 王五, age: 24, city: 广州}, ] print(users)输出是单行的上面我们已经看到了效果。它对人类阅读非常不友好尤其是字段多、记录多时。5.2 使用 pprint 美化输出Python 标准库中的pprint模块专为“美化打印数据结构”设计。它能够根据数据结构的嵌套深度自动缩进让字典列表变得层次分明# 文件路径demo/dict_list_pprint.py from pprint import pprint users [ {name: 张三, age: 28, city: 北京}, {name: 李四, age: 32, city: 上海}, {name: 王五, age: 24, city: 广州}, ] pprint(users)输出[{name: 张三, age: 28, city: 北京}, {name: 李四, age: 32, city: 上海}, {name: 王五, age: 24, city: 广州}]pprint会在容器内尽可能保持可读性宽度超过默认阈值时主动换行。你还可以通过参数控制输出宽度和缩进from pprint import pprint nested [ {name: 张三, tags: [vip, developer], address: {city: 北京, district: 海淀}}, {name: 李四, tags: [admin], address: {city: 上海, district: 浦东}}, ] pprint(nested, width60, sort_dictsFalse)sort_dictsFalse表示保持字典原有的键顺序。Python 3.8 以上支持此参数。width60让嵌套结构更容易被控制在可读宽度内。pprint适合开发调试验证阶段。它的输出目标是人眼不适合直接存入日志文件因为多行文本在日志系统中会被拆成多条事件。5.3 使用 json.dumps 输出规范格式当数据结构完全由 JSON 支持的字段构成字符串、数字、布尔值、字典、列表、None使用json.dumps()是更好的选择。它有两个优势格式标准、可以通过缩进让嵌套结构变得非常清晰。# 文件路径demo/dict_list_json.py import json users [ {name: 张三, age: 28, city: 北京}, {name: 李四, age: 32, city: 上海}, ] print(json.dumps(users, ensure_asciiFalse, indent2))输出[ { name: 张三, age: 28, city: 北京 }, { name: 李四, age: 32, city: 上海 } ]这里有两个关键参数必须说明。ensure_asciiFalse非常关键。如果不设置它JSON 模块默认会把所有非 ASCII 字符转成\uXXXX导致中文变成转义序列[ { name: \u5f20\u4e09, age: 28, city: \u5317\u4eac } ]这不是 bug而是 JSON 规范允许的表现形式。但在人的阅读视角里这种输出会给调试带来额外心智负担。所以处理含中文数据时建议设置ensure_asciiFalse。indent2或indent4控制缩进。设置为None时输出紧凑模式适合日志单行存储设置为数字时输出美化模式适合人眼阅读。json.dumps还经常用于数据“回显”比如接口联调时把请求参数或响应体打印到控制台服务端和客户端之间的数据结构是否一致一眼便能判断。5.4 使用 pprint 和 json 的边界有人会问pprint和json.dumps到底怎么选从适用场景来看pprint的适用范围更广。它能处理datetime、自定义对象、集合、元组等非 JSON 类型打印时尽量保留 Python 对象的结构感。json.dumps只支持 JSON 可序列化类型遇到datetime会直接抛TypeError。从格式标准来看json.dumps输出的是合法 JSON可以直接复制到在线解析工具、文档或接口调试器中。pprint的输出更接近 Python 字面量不适合作为交互数据。从日志友好度看单行 JSON 更适合日志聚合平台存储而美化后的 JSON 适合本地调试。实际项目常用组合是本地调试用美化 JSON线上日志用单行 JSON。再看一个自定义对象打印的例子# 文件路径demo/dict_list_custom.py from pprint import pprint from dataclasses import dataclass dataclass class User: name: str age: int city: str users [ User(张三, 28, 北京), User(李四, 32, 上海), ] print(users) # 直接打印依赖 __repr__ pprint(users) # pprint 同样依赖 __repr__运行结果[User(name张三, age28, city北京), User(name李四, age32, city上海)]dataclass自动生成了清晰的__repr__()所以直接打印不会出现object at 0x...。这说明一个工程经验给业务对象实现清晰的__repr__()是所有打印方案的基础。如果自定义类没有可读的__repr__()任何美化输出的效果都会打折扣。6. 在不同 Python 版本和终端中的差异列表打印的基础语法在所有 Python 3 版本中基本一致但如果你在 Python 2 的老项目或交互式环境中碰到问题需要留意几下几点。Python 2 中print是语句而不是函数写法是print nums不支持sep和end参数。从 Python 3 开始print变成了函数这才是现代 Python 的标准写法。如果你维护老项目看到print nums说明代码是 Python 2 风格建议统一迁移到 Python 3。另一个可能被忽视的差异是终端编码。在 Windows 的命令行窗口中默认编码可能是 GBK 或 GB2312。使用print输出中文列表时如果终端编码与 Python 标准输出的编码不一致会报UnicodeEncodeError。常见处理方法是设置环境变量PYTHONIOENCODINGutf-8# Windows PowerShell $env:PYTHONIOENCODING utf-8 python script.py # macOS / Linux PYTHONIOENCODINGutf-8 python script.py如果你使用 VS Code 或 PyCharm还需注意终端编码设置。多数情况下把 Python 文件保存为 UTF-8 并在 UTF-8 终端下运行就不会有编码问题。我们把不同场景下的打印方式与输出效果放到一个表中数据形态推荐打印方式输出特征典型使用场景小规模整型列表print(nums)或print(*nums)单行本地快速验证字符串列表print(, .join(tags))单行无引号日志字段展示字典列表人眼检查pprint(users)多行缩进本地调试字典列表接口联调json.dumps(users, ensure_asciiFalse, indent2)标准 JSON 多行接口数据核对字典列表线上日志json.dumps(users, ensure_asciiFalse)单行 JSON日志采集大量元素逐条处理for循环 日志每条独立业务日志7. 完整示例一个可复用的列表打印工具函数为了让你在真实项目里直接落地我整理了一个工具函数把前面讨论的多种策略组合起来。它不是复杂的类库而是一个放在utils/print_util.py中的通用函数。# 文件路径utils/print_util.py import json from pprint import pprint def print_list(data, titleNone, fmtauto, ensure_asciiFalse, indent2): 通用列表打印函数。 参数 data: list 或可迭代对象。 title: 可选标题输出前先打印。 fmt: auto / line / pretty / json / raw。 ensure_ascii: json 输出时是否转义非 ASCII 字符。 indent: json 缩进为 None 时输出单行。 if hasattr(data, __iter__) and not isinstance(data, (str, bytes, dict)): items list(data) else: items data if title: print(f {title} ) if fmt auto: if not items: print([]) return first items[0] if isinstance(first, dict): print(json.dumps(items, ensure_asciiensure_ascii, indentindent)) else: pprint(items) elif fmt line: print(, .join(str(item) for item in items)) elif fmt pretty: pprint(items) elif fmt json: print(json.dumps(items, ensure_asciiensure_ascii, indentindent)) elif fmt raw: print(items) else: raise ValueError(fUnsupported fmt: {fmt})这个函数的设计思路是fmtauto时自动判断如果列表元素是字典用 JSON 美化输出否则用pprint。fmtline时提供单行拼接适合元素简单且量少的情况。fmtpretty强制使用pprint。fmtjson强制使用 JSON 输出。fmtraw相当于普通print(items)。下面是调用示例# 文件路径demo/use_print_util.py from utils.print_util import print_list users [ {name: 张三, age: 28, city: 北京}, {name: 李四, age: 32, city: 上海}, ] print_list(users, title用户列表, fmtjson, indent2) print() print_list([1, 2, 3], title数字列表, fmtline)运行结果 用户列表 [ { name: 张三, age: 28, city: 北京 }, { name: 李四, age: 32, city: 上海 } ] 数字列表 1, 2, 3你可以把print_list放进项目公共工具目录在调试代码时统一调用避免每个文件里都写自己的打印风格。也可以继续扩展让它支持输出到指定文件、日志对象或远程日志平台。8. 日志场景中如何打印列表在实际后端服务里直接使用print()打印列表通常不是最佳实践。更规范的做法是通过logging模块输出并遵循“一条日志一条消息”的原则。因为日志系统ELK、Splunk 等对多行消息的处理方式不同有些平台会把多行记录拆开导致结构化检索失败。推荐的做法是在打印列表时先把列表序列化为单行 JSON再写入日志。# 文件路径demo/log_list.py import json import logging logging.basicConfig(levellogging.INFO, format%(asctime)s %(levelname)s %(message)s) logger logging.getLogger(demo) users [ {name: 张三, age: 28, city: 北京}, {name: 李四, age: 32, city: 上海}, ] logger.info(users%s, json.dumps(users, ensure_asciiFalse))运行结果2025-01-15 10:30:00,123 INFO users[{name: 张三, age: 28, city: 北京}, {name: 李四, age: 32, city: 上海}]它的好处是单行消息不会破坏日志聚合逻辑。JSON 格式便于日志平台做字段解析。ensure_asciiFalse保证中文日志可读。如果要从日志中还原数据直接把 JSON 部分复制出来用json.loads()分析即可。这里要提醒日志中输出完整列表存在信息泄露风险。如果列表包含用户手机号、邮箱、密码等敏感信息应该提前做脱敏处理只打印部分字段或掩码后的内容。另外日志消息应该使用延迟格式化也就是logger.info(users%s, data_str)而不是logger.info(users%s % data_str)。前一种写法在日志级别不满足时不会执行字符串格式化能减少无谓开销。9. 运行结果与效果验证写到这里你可能已经复制了一部分代码。下面用一个完整案例验证效果。准备工作是在项目目录下创建两个文件project/ ├── utils/ │ └── print_util.py └── demo/ ├── use_print_util.py └── log_list.py先运行use_print_util.pypython demo/use_print_util.py预期输出应该包含两段内容第一段是带标题的 JSON 格式化用户列表第二段是逗号分隔的数字列表。如果输出与预期一致说明工具函数没问题。再运行 log_list.pypython demo/log_list.py预期输出是一条包含INFO级别和时间戳的日志后面跟着单行 JSON 数据。如果运行失败按下面的顺序排查第一步检查 Python 是否安装成功执行python --version。第二步检查当前目录结构是否正确。utils目录下需要有__init__.py吗Python 3 的隐式命名空间包通常不需要但为了兼容旧项目建议在utils目录下创建空文件__init__.py。第三步如果报ModuleNotFoundError: No module named utils说明启动脚本时的工作目录不在project/下。在project/根目录运行命令即可。第四步如果输出中文乱码按第 6 节说明设置PYTHONIOENCODINGutf-8。效果验证清单: 1. use_print_util.py 输出 JSON 是否有缩进 2. use_print_util.py 输出中文是否可读 3. log_list.py 输出是否单行 4. 修改 fmt 参数效果是否切换 5. 传入空列表 [] 是否正常输出如果以上都通过说明你的列表打印环境已经具备生产可用性。10. 常见问题与排查思路下面汇总高频问题。这些问题来自日常开发中最容易踩坑的点建议直接收藏。问题现象可能原因排查方式解决方案打印列表中文变成\u5f20\u4e09json.dumps()默认ensure_asciiTrue查看json.dumps调用参数设置ensure_asciiFalse自定义对象显示object at 0x...类未实现__repr__()检查类定义使用dataclass或添加__repr__()Windows 终端打印中文报编码错误标准输出编码与终端编码不一致查看完整报错信息设置PYTHONIOENCODINGutf-8join()报TypeError列表中含有非字符串元素检查列表类型使用生成器表达式str(item)转换打印生成器对象只能看到内存地址生成器并未被消费为列表检查变量类型先list(generator)再打印日志平台的列表日志跨行错乱美化 JSON 包含换行符查看日志平台对多行事件的处理配置日志中使用单行 JSON列表打印到日志后无法字段检索日志格式不规范检查日志后端解析规则结构化 JSON 日志使用print(*list)展开超长列表报错参数数量或内联显示过大分析报错栈改用for循环或切片分批输出控制台反复输出超长列表滚动查看困难数据量过大明确是否需要全量输出切片list[:10]或只输出统计信息Flask/Django 视图打印列表无输出输出被 Web 服务框架捕获查看服务日志文件使用app.logger或标准logging打印时字典顺序和声明不一致Python 3.7 前字典无序或sort_dicts默认排序查看字典类型版本使用 Python 3.7需要时传sort_dictsFalse11. 性能与安全性注意事项在深入使用列表打印后还有两个容易被忽略的点性能和敏感数据安全。11.1 不要无限制打印大列表线上代码中如果一个列表有百万级数据使用print()或logger.info()全量输出会占用大量 IO 和时间。更合理的方式是只打印“摘要信息”# 文件路径demo/summary_list.py items list(range(1000000)) # 不要直接 print(items) print(ftotal{len(items)}, first_10{items[:10]}, last_10{items[-10:]})运行结果total1000000, first_10[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], last_10[999990, 999991, 999992, 999993, 999994, 999995, 999996, 999997, 999998, 999999]在处理接口返回、分析大批量数据时这种摘要式输出能快速帮助定位问题又不会让控制台和日志系统承受压力。11.2 打印对象前先脱敏当列表元素是用户信息用户名、手机号、身份证号、地址时直接全量打印并写入日志会引入信息泄露风险。通用做法是定义一个脱敏函数在打印前替换关键字段# 文件路径demo/desensitize.py import json def mask_user(user): masked dict(user) phone str(masked.get(phone, )) if len(phone) 11: masked[phone] phone[:3] **** phone[7:] return masked users [ {name: 张三, phone: 13812345678}, {name: 李四, phone: 13987654321}, ] safe_users [mask_user(user) for user in users] print(json.dumps(safe_users, ensure_asciiFalse, indent2))输出[ { name: 张三, phone: 138****5678 }, { name: 李四, phone: 139****4321 } ]在真实项目中脱敏函数应该被放在公共安全模块里统一使用而不是在业务代码中临时拼字符串。这样可以避免有人绕过脱敏逻辑把完整手机号打到日志里。11.3 不要打印不可信的外部输入如果列表数据来自用户上传文件、第三方接口或公网请求打印前要谨慎。恶意构造的超长字符串可能导致控制台或日志平台存储异常。更关键的是如果直接把外部输入拼接到日志消息中可能造成日志注入问题比如攻击者在字符串里嵌入换行符伪造日志记录。处理思路是限制单条日志的最大长度或者对外部字符串做转义。实践中单行日志常见做法是保留 JSON 结构但对字段内容设置最大长度# 文件路径demo/limit_log.py import json def safe_log_data(data, max_len200): text json.dumps(data, ensure_asciiFalse) if len(text) max_len: return text[:max_len] ...(truncated) return text payload [{content: x * 10000}] print(safe_log_data(payload))输出类似[{content: xxxxxxxxxx...(truncated)这样既保留了可读性又防止日志被单条超长内容打爆。12. 把打印能力融入工程实践一个真正好用的列表打印方案不只是写一个工具函数还要考虑在项目中如何统一规范。这里给出几条工程建议。12.1 统一调试辅助函数在团队项目里创建utils/debug_utils.py集中存放打印相关工具函数。避免每个成员都写各自的 print 风格。可以在函数内部加入环境判断让“本地开发时打印详细内容、生产环境只打印必备日志”成为默认策略。# 文件路径utils/debug_utils.py import os import json from pprint import pprint DEBUG os.getenv(DEBUG, 0) 1 def debug_print_list(title, data): if not DEBUG: return print(f {title} ) first data[0] if data else None if first and isinstance(first, dict): pprint(data) else: print(data)推荐做法是让调试信息受环境变量控制而不是每次改代码、改完又忘删。12.2 在接口联调时返回数据检查如果你在用 Python 写后端接口处理course/course/list这类列表接口时返回给前端的数据往往是一个列表。接口联调出错时先在服务端打印响应体# 文件路径demo/flask_response_debug.py from flask import Flask, jsonify app Flask(__name__) app.route(/course/list) def course_list(): courses [ {id: 1, name: Python 入门}, {id: 2, name: 数据结构}, ] response_data {code: 0, data: courses} from utils.print_util import print_list print_list(courses, titlecourse list response, fmtjson, indent2) return jsonify(response_data) if __name__ __main__: app.run()如果前端报“数据为空”而你看到服务端列表有内容问题出在序列化或字段命名上。如果服务端本身就打印空列表问题出在查询或传参上。这个小小的打印习惯能把“接口联调问题”快速分成前后端两类。12.3 结合数据校验自定义对象打印之外另一种常见场景是打印 Pydantic 模型或dataclass列表。Pydantic 模型自带model_dump()方法可以先把对象转成字典列表再打印dataclass可以使用dataclasses.asdict()转换。示例# 文件路径demo/model_dump.py from dataclasses import dataclass, asdict dataclass class User: name: str age: int city: str users [User(张三, 28, 北京), User(李四, 32, 上海)] dict_list [asdict(user) for user in users] from pprint import pprint pprint(dict_list)在这个设计下业务层尽量不直接打印对象而是先转成标准字典再决定输出格式。这样打印逻辑与数据结构解耦未来即使修改字段名也只影响转换层。12.4 自定义__repr__()是基础工程最后最重要的一条给业务模型写清晰的__repr__()是回报率极高的投入。无论你用哪种打印方式都会受益于对象本身能够自我描述。实现时不要只打印内存地址而要把关键字段拼出来。# 文件路径demo/custom_repr.py class User: def __init__(self, name, age, city): self.name name self.age age self.city city def __repr__(self): return fUser(name{self.name!r}, age{self.age!r}, city{self.city!r}) users [User(张三, 28, 北京), User(李四, 32, 上海)] print(users)输出[User(name张三, age28, city北京), User(name李四, age32, city上海)]有了这样的基础后续所有定制打印方案才能发挥真正效果。13. 总结与后续学习方向列表打印看起来是人人都知道的基础话题但真正把它做对需要理解 Python 对象格式化机制、字符串表示与容器递归输出的关系以及不同场景控制台、日志、接口联调对输出格式的不同要求。表面上是“简单功能”背后实际上是一套数据展示规范。你在项目里可以先做三件事第一检查现有代码中直接print(list)的地方评估是否有数据量过大、中文不可读、日志跨行等问题第二把公共的列表打印工具函数引入项目并统一调用第三为业务模型补上清晰的__repr__()为敏感数据补上脱敏过滤。继续深入学习时可以围绕三个方向展开一是pprint模块的更多参数与PrettyPrinter类源码二是日志处理中的 JSON Formatter 实践三是 Pydantic 模型在打印与序列化时的高级用法。数据展示方式看似不起眼但真正影响着你每天定位问题的速度。