ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Python列表打印详解:从print到JSON格式化与工程实践

Python列表打印详解:从print到JSON格式化与工程实践 这次我们来看一个看起来很基础、但在实际开发里高频踩坑的话题Python 中打印列表Printing Lists。文章标题只有两个词但在真实项目里它通常对应三种需求一是把 list 完整打印出来用于调试二是把 list 按指定格式输出成日志、文件或接口返回三是把一个很大的列表打印成人类易读的表格或 JSON。如果只是写print(list)然后收工往往会遇到中文乱码、输出被截断、嵌套结构看不清、大量数据刷屏导致程序变慢等问题。本文会围绕“打印列表”这个主题从最基础的输出方法开始讲到格式化、JSON 序列化、表格化、批量输出、日志接入、大列表打印性能观察和常见问题排查。无论你是刚学 Python 的初学者还是写接口、写脚本、处理数据的开发都可以直接对照操作。下面先说结论Python 打印列表没有唯一标准方式关键看你希望输出给人看还是给机器用决定输出方式时优先关注数据规模、可读性和是否需要后续解析。1. 核心能力速览在 Python 生态中“打印列表”通常搭配的核心能力并不仅仅是print()本身还包含pprint、json.dumps、str.join、列表推导式、日志模块等手段。这里先把不同方式的核心能力整理成一张表。能力项说明基本输出print(my_list)适合小规模列表直接查看格式化输出使用 f-string、format()或join()控制分隔符和样式循环逐行打印适合日志输出、逐条处理时查看元素嵌套结构美化使用pprint或json.dumps(..., indent2)中文编码处理设置ensure_asciiFalse或调整终端编码转字符串存储str(list)便于写入文件但不利于二次解析表格化展示pandas、tabulate、rich 可以输出更可读的表格日志采集logging 模块配合 list 元素遍历避免禁用打印后丢失状态批量任务读入多个 list逐条格式化输出到文件或接口性能优化大列表下避免逐元素print造成大量 IO 阻塞这些能力覆盖了绝大多数开发场景日常调试、接口返回数据检查、自动化脚本输出、日志采集、数据报表导出。2. 适用场景与使用边界打印列表是一个通用能力但不同场景适用不同写法。日常调试时最快的做法就是print(list)或者print(list[:5])。这种做法的优点是零依赖、改动小缺点是在数据量很大的情况下控制台会非常混乱。如果是接口联调阶段需要查看后端返回的列表字段建议直接使用json.dumps()格式化输出因为 JSON 格式既能在终端看得清楚也方便复制到 Postman、Apifox 等工具里继续处理。在写日志系统时print 不是好选择。print 默认输出到标准输出无法按级别过滤也不容易加时间戳和调用位置。正确做法是使用logging模块把 list 内容逐条写入日志或者把 JSON 字符串写入日志文件。这里要特别注意一个使用边界不要把接口返回中的敏感字段、token、用户隐私信息直接print到日志里。虽然本地调试方便但如果日志文件被上传、被其他人查看就可能造成信息泄漏。批量任务场景中打印列表往往不是终点。常见需求是“读一个包含多个列表的文件按行清洗后输出到另一个文件”这时候 print 只能作为过程观察手段真正的落盘结果应该写进文件或用csv、json模块保存。如果你在处理客户数据、人脸特征向量、语音配置或其他敏感素材还必须确保数据脱敏和授权后才输出到共享环境。从这些边界来看掌握打印列表并不仅仅是记住几个函数而是需要根据输出对象是人还是机器、数据是否敏感、数据量是否大来选择方案。3. 环境准备与前置条件这个主题不依赖昂贵的硬件。操作系统中只要安装了 Python 3.8 以上版本即可实测绝大多数开源项目也已经迁移到 Python 3.10 或 3.11所以建议优先使用 3.10 以上版本。无需 GPU无需虚拟机普通 Windows、Linux、macOS 都可以跑通。建议先创建一个单独目录用于测试避免测试脚本散落在各处mkdir print_list_demo cd print_list_demo python -m venv venv在 Windows 系统下激活虚拟环境venv\Scripts\activate在 Linux 或 macOS 下激活虚拟环境source venv/bin/activate文章中部分示例需要额外库例如tabulate、requests、pandas。如果你只需要掌握基础方法安装 tabulate 就够了pip install tabulate requests同时需要关注终端编码。Windows 终端如果出现中文乱码可以在运行命令前设置 UTF-8 环境变量set PYTHONUTF81 python test.pyPowerShell 环境下可以等价执行$env:PYTHONUTF81 python test.py4. 打印 Python 列表的基础操作与代码示例这是本文核心章节。我们从最简单的print(list)开始然后逐步扩展到工作中真正会用的格式化写法。4.1 直接打印整个列表假设有一个字符串列表和一个数字列表# basic_print.py students [张三, 李四, 王五, 赵六] scores [89, 93, 78, 84] print(students) print(scores)运行后输出[张三, 李四, 王五, 赵六] [89, 93, 78, 84]这里看到的是 Python 的repr形式。它会保留引号和括号好处是复制到 Python 环境里还能恢复成列表适合快速调试坏处是可读性一般如果列表很长就变成一长串。很多时候我们只关心前面几个元素可以切片打印print(students[:2]) print(scores[-2:])输出[张三, 李四] [78, 84]4.2 循环逐行打印如果列表元素代表日志中的一行记录逐行打印更清晰# loop_print.py students [张三, 李四, 王五, 赵六] for student in students: print(student)输出张三 李四 王五 赵六如果希望同时打印索引就使用enumeratefor idx, student in enumerate(students, start1): print(f{idx}. {student})输出1. 张三 2. 李四 3. 王五 4. 赵六这在很多实际场景里很有用例如给任务队列编号、给排行榜序号、显示执行进度。4.3 使用 join 控制分隔符join()是最常用的字符串列表打印方式。它可以把列表拼接成一行字符串并指定分隔符。# join_print.py tags [Python, 开发, 脚本] print(、.join(tags))输出Python、开发、脚本如果元素不是字符串需要先转换否则会抛出TypeError: sequence item 0: expected str instance, int found。推荐使用列表推导式numbers [1, 2, 3, 4] print(, .join(str(num) for num in numbers))输出1, 2, 3, 4如果希望拼接后元素之间换行可以直接用\n作为分隔符fruits [苹果, 香蕉, 橙子] print(\n.join(fruits))输出苹果 香蕉 橙子join()本质上是一次字符串拼接比循环里反复使用print(..., end )效率更高也是推荐做法。4.4 使用 pprint 美化嵌套列表嵌套列表直接使用print往往会把整个结构挤在一起matrix [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] print(matrix)输出[[1, 2, 3], [4, 5, 6], [7, 8, 9]]当元素增加时不容易看清子列表结构。使用pprint可以自动换行并保持缩进from pprint import pprint matrix [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] pprint(matrix)输出[[1, 2, 3], [4, 5, 6], [7, 8, 9]]如果列表元素本身带有较长的字典结构pprint的可读性优势会更明显users [ {name: 张三, age: 25, tags: [管理员, 后端]}, {name: 李四, age: 30, tags: [开发, 运维]}, ] pprint(users, width40)输出会按照嵌套结构进行折行便于检查字段。4.5 使用 json.dumps 打印 JSON 友好的列表接口返回的数据往往是列表嵌套字典像这样user_list [ {id: 1, name: 张三, courses: [Python, MySQL]}, {id: 2, name: 李四, courses: [Java]}, ]直接print(user_list)会输出一行极长的内容。推荐使用json.dumpsimport json print(json.dumps(user_list, ensure_asciiFalse, indent2))这里关键参数有两个ensure_asciiFalse让中文正常显示而不是输出\u5f20\u4e09。indent2按两层空格缩进每个字典字段单独换行。输出[ { id: 1, name: 张三, courses: [ Python, MySQL ] }, { id: 2, name: 李四, courses: [ Java ] } ]这种格式可以直接粘贴到接口调试工具中便于前端、后端协作确认数据结构。需要说明的是json.dumps默认要求列表中的字典键是字符串等基本类型如果包含自定义对象或set需要先做数据清洗否则会报TypeError。4.6 打印自定义对象列表实际开发中列表里往往不是字符串或字典而是自定义类的对象。例如class Task: def __init__(self, task_id, name, status): self.task_id task_id self.name name self.status status tasks [ Task(1, 导入数据, success), Task(2, 导出报表, failed), ]只使用print(tasks)输出的是对象的地址信息不够直观。解决办法是为类实现__repr__方法class Task: def __init__(self, task_id, name, status): self.task_id task_id self.name name self.status status def __repr__(self): return fTask(id{self.task_id}, name{self.name!r}, status{self.status!r}) print(tasks)输出[Task(id1, name导入数据, statussuccess), Task(id2, name导出报表, statusfailed)]工程化一点的做法是把列表转成字典后再输出print([task.__dict__ for task in tasks])也有团队习惯使用dataclasses配合asdict统一处理。这里建议优先考虑是否需要被日志采集或接口解析如果是日志展示__repr__足够如果要进一步写入数据库就转成 dict。5. 常见业务场景实操掌握了基础方法之后我们再把它放在具体场景里看。5.1 接口返回列表的检查假设你调用了一个接口返回结构是{code: 0, data: {course_list: [{course_id: 1, course_name: Python}, ...]}}。调试时想确认course_list是否符合预期可以这样写import json import requests resp requests.get(http://127.0.0.1:8000/api/course/list) data resp.json() course_list data.get(data, {}).get(course_list, []) print(接口返回课程数量:, len(course_list)) print(json.dumps(course_list[:2], ensure_asciiFalse, indent2))思路是先打印总数再截取前两条格式化输出避免接口返回几千条数据时控制台直接卡死。判断成功的标准是能看到明确的课程 ID、名称并且数量符合数据库查询结果。常见问题是接口根本没返回course_list字段代码写错层级抛出AttributeError: NoneType object has no attribute get或者页面报错No static resource course/course/list for request /course/course/list。这类问题本质是后端请求路径或路由配置错误打印列表前就应该先确认接口地址和返回包结构。5.2 批量任务输出在批处理任务里常见情况是有一个日志字符串列表希望每隔一段时间显示进度同时把最后结果写入文件。这里可以先做一个函数把输出结果同时送到屏幕和文件# batch_output.py import sys def write_list_to_file(file_path, data_list): with open(file_path, w, encodingutf-8) as f: for item in data_list: f.write(str(item) \n) print(f已写入 {len(data_list)} 行到 {file_path}) result [任务1: 成功, 任务2: 成功, 任务3: 失败] write_list_to_file(result.log, result)在批量任务中不建议每一行都既调用print又调用文件写入因为大量 IO 会拖慢速度。可以先在内存里组织好字符串再一次性写入或使用BufferedWriter。如果你希望看到实时进度可以每处理完一批就打印一次汇总信息。5.3 表格化打印当列表元素是固定的业务字段时表格输出比 JSON 更适合人眼阅读。使用tabulate可以快速实现# table_print.py from tabulate import tabulate users [ {name: 张三, age: 25, city: 北京}, {name: 李四, age: 30, city: 上海}, {name: 王五, age: 28, city: 深圳}, ] headers [姓名, 年龄, 城市] rows [[u[name], u[age], u[city]] for u in users] print(tabulate(rows, headersheaders, tablefmtgrid))输出------------------------ | 姓名 | 年龄 | 城市 | | 张三 | 25 | 北京 | ------------------------ | 李四 | 30 | 上海 | ------------------------ | 王五 | 28 | 深圳 | ------------------------tablefmt可以切换成plain、simple、github、markdown等格式。如果项目里已经使用 pandas也可以直接print(df.to_string(indexFalse))。表格打印适合数据行数几十到几百时使用几千行以上就不适合塞进控制台了更合理的是输出到 CSV 或 HTML。5.4 复杂嵌套的展开复杂嵌套列表不只有“列表套列表”还可能包含空值、元组、集合。集合没有固定顺序JSON 也不支持直接序列化集合。处理时先转换成可预测的结构import json raw_data [ {name: 张三, tags: {开发, 后端}}, {name: 李四, tags: set()}, ] def clean_item(item): return { name: item[name], tags: sorted(item[tags]), } cleaned [clean_item(item) for item in raw_data] print(json.dumps(cleaned, ensure_asciiFalse, indent2))如果不先处理集合运行时会出现Object of type set is not JSON serializable。这类问题在数据清洗脚本里很常见提醒我们在打印前先想清楚数据结构。6. 接口 API 与批量任务中的数据打印如果把“打印列表”放到接口服务场景通常不是直接用print输出到终端而是关注服务返回列表数据时如何记录日志、如何做请求参数校验、如何批量输出。下面给出一套通用示例路径和参数需要根据实际项目调整。6.1 带请求日志的接口服务示例这里使用 Flask 写一个最小示例用于演示接收请求后从数据库或内存拿到一个 course_list打印请求参数和返回列表数量。# fl_demo.py from flask import Flask, request, jsonify import logging logging.basicConfig(levellogging.INFO, format%(asctime)s %(levelname)s %(message)s) app Flask(__name__) ALL_COURSES [ {course_id: 1, course_name: Python 基础}, {course_id: 2, course_name: 数据结构和算法}, {course_id: 3, course_name: Web 开发}, ] app.route(/api/course/list, methods[GET]) def course_list(): page request.args.get(page, 1, typeint) size request.args.get(size, 10, typeint) start (page - 1) * size end start size result ALL_COURSES[start:end] logging.info(page%s size%s result_count%s, page, size, len(result)) return jsonify({code: 0, data: result, total: len(ALL_COURSES)}) if __name__ __main__: app.run(host127.0.0.1, port8000, debugFalse)启动服务python fl_demo.py然后访问接口curl http://127.0.0.1:8000/api/course/list?page1size2观察服务端日志和返回结果。重点不是 Flask 本身而是不要把整个大列表直接打进日志而是打印分页参数、结果条数、耗时这些摘要信息如果确实需要打印返回数据也只打印前几条。6.2 批量输出列表到文件接口开发中常常需要把查询结果导出成 CSV。用 Python 自带的csv模块写批量列表比较稳妥# export_csv.py import csv def export_rows_to_csv(file_path, headers, rows): with open(file_path, w, encodingutf-8-sig, newline) as f: writer csv.writer(f) writer.writerow(headers) writer.writerows(rows) headers [course_id, course_name] rows [ [1, Python 基础], [2, 数据结构], ] export_rows_to_csv(courses.csv, headers, rows) print(导出完成)Excel 打开中文 CSV 时如果出现乱码可以使用utf-8-sig编码。这里补充说明如果列表是字典列表可以用csv.DictWriter字段顺序由fieldnames控制。批量任务中常见的问题是写入到一半报编码错误、文件被占用、导出的字符串带了多余引号。排查时可以先打印预览几行再决定转换逻辑。6.3 批量打印到日志系统如果是定时脚本或后台任务不建议在循环里print。建议统一使用 logging并控制日志级别import logging logging.basicConfig( levellogging.INFO, format%(asctime)s %(name)s %(levelname)s %(message)s, ) user_ids [1001, 1002, 1003] for idx, user_id in enumerate(user_ids, start1): logging.info(processing user_id%s progress%s/%s, user_id, idx, len(user_ids))这段代码会在日志中输出带时间戳的行适合排查任务执行到哪一步停止。批量任务卡住时通常先看最后一条日志内容再检查对应数据源和中间件状态。7. 资源占用与性能观察print的输出速度看起来很快但在超大列表下可能成为瓶颈。原因是每次print都要向标准输出写入数据如果输出到终端还受终端渲染速度影响如果输出被重定向到管道或文件也可能因为频繁 IO 变慢。建议先用时间观察列表输出的耗时# perf_test.py import time big_list list(range(100000)) start time.perf_counter() print(big_list[:100]) print(耗时:, time.perf_counter() - start)这里只打印了前 100 个元素做观察避免全量打印刷屏。如果你确实需要全量打印到一个文件用于分析可以直接使用文件写入而不是把终端输出重定向逻辑会更清晰。大列表逐行打印的性能差异# perf_compare.py import time big_list [str(i) for i in range(50000)] start time.perf_counter() # 方式一join 拼接后一次输出 chunk \n.join(big_list) print(chunk[:100]) # 只取一部分用于演示 join_spent time.perf_counter() - start start time.perf_counter() for item in big_list[:100]: print(item) loop_spent time.perf_counter() - start print(fjoin 方式耗时约: {join_spent:.6f}s) print(f循环 print 方式耗时约: {loop_spent:.6f}s)严格来说两者不能直接在“输出完整列表”这个任务上等同因为示例都只观察了前 100 项。但在实践中如果要把 5 万行全部写入文件使用join拼接一次写入通常会比在 Python 循环里逐条调用print更快。更稳妥的方法是使用 IO 缓冲例如with open(output.txt, w, encodingutf-8) as f: for item in big_list: f.write(item \n)这样可以避免终端渲染开销。如果你在 Windows 的 cmd 或 PowerShell 里运行大量 print有时候还会看到输出行被截断或滚动缓慢这通常是终端缓冲区限制不是 Python 程序本身出错。显存之类的话题在本主题里不涉及。如果要类比可以关注的是内存、CPU、IO 三个指标创建很大的列表本身占内存逐元素字符串拼接耗时更多是因为反复创建新字符串和频繁 IO输出重定向到文件时磁盘写入速度是主要瓶颈。观察指标可以使用 Python 内置tracemalloc或系统任务管理器。性能建议可以总结成一句话小列表直接打印中等列表先格式化再打印大列表避免打印到屏幕改为写文件或抽样输出。8. 常见问题与排查方法打印列表最常遇到的问题很多不在 Python 语法本身而在终端、编码、数据结构或输出方式。下面列出排查表。问题现象可能原因排查方式解决方案中文显示为\u5f20\u4e09json.dumps默认ensure_asciiTrue查看代码里是否传了ensure_asciiFalse添加ensure_asciiFalse终端中文乱码终端编码不是 UTF-8设置PYTHONUTF81后重新运行使用chcp 65001或set PYTHONUTF81TypeError: sequence item 0: expected str instance, int found列表元素不是字符串直接调用了join()检查元素类型使用, .join(str(x) for x in nums)打印结果被省略号截断IDE 或终端输出长度限制查看 IDE 输出缓冲区设置调整 PyCharm 控制台“Cyclic buffer”或者用文件方式输出输出一闪而过脚本执行完成后终端关闭运行方式问题使用 IDE 运行或在命令末尾添加input()打印自定义对象地址而不是内容类没有实现__repr__查看源码添加__repr__或转成字典自定义对象 JSON 序列化失败对象类型不是 JSON 支持类型找到json.dumps调用位置手动转换成 dict、list、str打印结果顺序和预期不符中间使用了set或无序集合格式化前打印中间对象先转成list或使用sorted()print执行很慢每个循环都调用print且数据量很大观察任务耗时批量拼接后一次输出或写日志文件调用接口后返回列表为空接口路径错误或后端过滤条件不对先打印接口返回原始包使用curl测试接口路径与参数列表数据被重复打印循环中没有去重或重复执行代码块检查for和函数调用范围在函数外层打印或使用集合去重额外提一个常见误区有些新手在打印列表时会把print和操作系统里的打印服务混淆。搜索引擎里高频出现的print spooler 启动后自动停止是 Windows 打印队列服务问题和 Python 的print只是同名不同义。搜索报错时需要区分是运行时错误、打印机服务错误还是接口返回错误。搜索日志时要带上完整的异常堆栈或接口返回原文。另外打印list时如果出现IndexError: list index out of range通常不是 print 本身的问题而是列表长度比预期小。排查时先打印len(list)再检查切片边界。例如print(列表长度:, len(data)) print(尾部三个元素:, data[-3:])使用try-except捕获异常时尽量把列表长度和当前位置打印在 except 块外面否则无法定位触发点。9. 最佳实践与使用建议综合上面的内容这里给出一套可以在项目中直接使用的打印列表最佳实践。第一把“调试输出”和“正式输出”分开。调试阶段可以用print但提交代码前应该清理或改成logging.debug。批量脚本中要保留过程日志建议统一用import logging logging.basicConfig(levellogging.DEBUG) logging.debug(当前列表前 10 项: %s, data[:10])第二先定义输出目标。给人看优先使用pprint或tabulate给接口或文件解析优先使用json.dumps、CSV 或纯文本给日志归档优先使用 logging给终端快速查看直接print(list[:5])即可。第三所有输出都要考虑数据规模。可以封装一个通用函数def safe_print_list(data_list, limit10): length len(data_list) print(flist length: {length}) if length limit: print(data_list[:limit]) else: print(data_list)第四中文场景统一设置ensure_asciiFalse和 UTF-8 编码避免开发机器上正常、部署服务器上乱码。Windows 服务器尤其要注意因为它默认编码可能不是 UTF-8。第五避免在循环内频繁写日志或打印。高性能的批量任务中可以在每个任务完成时打印摘要而不是把每个中间状态都输出。出错时再用异常信息补充具体任务内容。第六涉及隐私或版权数据时打印前先截断或打码。例如电话号、身份证号、人脸特征向量、声音特征等敏感字段不应该直接输出完整值应该输出138****0000这类掩码。第七如果列表内容来自网络请求打印前要处理可能的None和异常类型。比如for item in raw_list: if not isinstance(item, dict): logging.warning(非 dict 数据跳过: %s, type(item)) continue print(item.get(name))这些建议不复杂但可以减少大量线上排障时间。10. 总结与下一步回到开头的问题打印列表这件事并不只是print(列表)一行代码那么简单。真正值得掌握的是根据使用场景决定输出格式控制数据规模处理好编码和序列化问题同时为后续的文件、接口或日志系统留好扩展口。如果你刚开始接触 Python建议先跑通 4.1 到 4.6 的基础代码重点练习join和json.dumps两种方式因为它们在脚本开发里出现频率最高。如果已经在做接口联调或数据处理建议重点看第 5 节、第 6 节和第 8 节把“列表长度 抽样 格式化成 JSON/表格”这几个动作养成习惯。最容易踩的坑是中文乱码和自定义对象无法 JSON 序列化遇到异常时先打印长度和元素类型再决定解决方案。下一步可以从三个方向继续扩展一是用logging替换所有项目里的调试print二是把输出逻辑封装成统一工具模块比如output_helper.py三是学会使用rich库打印更漂亮的控制台表格和树形结构。这些都和打印列表相关但在这个核心语法之上又多了工程化能力。建议先把本文的示例跑通再按自己的业务需求修改函数参数和输出目录。这份内容可以直接当作团队内部“Python 输出规范”的参考也可以作为接口联调前的自检清单。如果后续遇到更具体的报错建议带着完整堆栈和前后代码片段去排查大部分列表打印问题都能在 10 分钟内定位。
返回列表