Python pickletools.dis 怎样查看 pickle 字节码结构
排查一个 .pkl 文件时,我更愿意先看它的协议操作码,再决定是否需要恢复对象。Python 的 pickletools.dis() 正好负责这一步:它把 pickle 字节流展开成带位置、操作码和参数的符号化文本,不要求先执行反序列化逻辑。
如果目标是“看 pickle 里面大概写了什么、用了哪个协议、哪些位置引用了 memo”,用pickletools.dis或python -m pickletools;如果目标是得到 Python 对象,才涉及pickle.load或pickle.loads。来源不可信时不要跨过这个安全边界。
官方文档:https://docs.python.org/3/library/pickletools.html
先把“查看结构”和“恢复对象”分开
pickle 是面向 Python 对象的二进制序列化协议,操作码里可能包含类型、字符串、容器构造和全局名称等信息。pickletools 的职责是分析这些操作码;它不等于把字节流恢复成原来的对象。
命令行最省事的写法如下。这里的 # 是 shell 注释,只说明命令用途,不是输入文件的一部分:
# 只展开 pickle 操作码,不调用 pickle.load 或 pickle.loads
python -m pickletools sample.pkl
我在处理来源不明的文件时会先保留这份文本输出。这样能先观察协议版本、字符串和容器相关操作码,再决定是否需要交给隔离环境做进一步处理。不要为了“确认内容”直接把文件交给 pickle.load。
最小配方:用 pickletools.dis 输出可读结构
dis 接受 pickle 字节串或文件对象,默认把符号化反汇编写到标准输出。下面的示例只用本地构造的可信数据生成演示字节流;它的重点是查看协议结构,而不是展示反序列化。
import io
import pickle
import pickletools
# 只为演示生成可信的本地 pickle 字节流,不要对不可信输入调用 loads。
payload = pickle.dumps(
{"name": "demo", "items": [1, 2]},
protocol=4,
)
# 把 bytes 包成二进制文件对象,dis 会把操作码写到标准输出。
pickletools.dis(io.BytesIO(payload), annotate=1)
输出通常会包含偏移位置、操作码名称、参数和栈级别信息。annotate=1 会在输出中追加简短的操作码说明,便于第一次阅读;如果你只想保留紧凑结果,可以省略它。

文件输入和输出位置怎么控制
分析现成文件时,不需要先把文件读成一个巨大的 bytes。直接把以二进制模式打开的文件对象传给 dis 即可。输出也可以从标准输出改到 io.StringIO,便于保存、截取或交给日志系统。
import io
import pickletools
# 以 rb 打开文件,避免文本编码层改变原始 pickle 字节。
with open("sample.pkl", "rb") as source:
report = io.StringIO()
# 把反汇编文本写入内存缓冲区,indentlevel 控制嵌套层级缩进。
pickletools.dis(
source,
out=report,
indentlevel=2,
annotate=1,
)
# 这里只读取分析文本,不会把 pickle 恢复成 Python 对象。
print(report.getvalue())
这里有三个容易混淆的参数:
out是文本输出对象,不是新的 pickle 文件;indentlevel影响嵌套结构的显示缩进,不改变原始字节流;annotate是注释列位置提示,非零值会让操作码旁边多出简短说明。
需要筛选记录时改用 pickletools.genops
dis 适合人眼通读;如果我想找出某个位置、某类操作码或某个参数,就会改用 genops。它逐项返回 (opcode, arg, pos),其中 opcode 是 OpcodeInfo 对象,arg 是已解码的参数,pos 是该操作码在字节流中的偏移。
import pickletools
# 逐项读取操作码记录,只做结构分析,不恢复对象。
with open("sample.pkl", "rb") as source:
for opcode, arg, pos in pickletools.genops(source):
# 只打印稳定的名称、参数和偏移,方便后续筛选。
print(f"pos={pos:04d} name={opcode.name} arg={arg!r}")
例如,排查协议版本时可以关注 PROTO;分析引用关系时可以关注 PUT、GET、BINPUT 或 BINGET。不要把这些名字当作 Python 业务字段,它们是 pickle 协议层的操作码。

连续分析和 optimize 该怎么选
如果多个 pickle 片段来自同一个 pickler,dis 的 memo 参数可以复用同一个字典,让连续反汇编共享引用上下文。它适合分析一组有关联的片段,不代表线程安全,也不会把多个文件自动合并。
import io
import pickletools
# 同一分析会话复用 memo,用来保留连续 pickle 片段的引用上下文。
memo = {}
first = io.BytesIO(b"...")
second = io.BytesIO(b"...")
# 示例中的字节流必须替换为来自同一 pickler 的可信数据。
pickletools.dis(first, memo=memo, out=io.StringIO())
pickletools.dis(second, memo=memo, out=io.StringIO())
如果你的目标是得到语义等价但更紧凑的 pickle 字节串,可以了解 pickletools.optimize()。它会返回一个新的等价字节串并移除未使用的 PUT 操作码;这属于整理序列化结果,不是查看报告的必要步骤,也不应拿来处理未经信任的输入后再继续反序列化。
这几个边界最容易踩坑
| 目标 | 适合的入口 | 需要注意 |
|---|---|---|
| 查看协议和操作码 | python -m pickletools 或 pickletools.dis | 输出是结构说明,不是恢复后的对象 |
| 筛选偏移和参数 | pickletools.genops | arg 已被解析成 Python 值,但仍处于分析上下文 |
| 保留连续引用信息 | dis(..., memo=同一个字典) | 只对具有关联的连续片段有意义 |
| 恢复 Python 对象 | pickle.load 或 pickle.loads | 只处理明确可信且完整的输入 |
特别要注意,pickletools 的“更安全”只表示它专注于反汇编、不执行 pickle 字节码;它不是对输入来源的认证。文件是否被篡改、内容是否符合业务预期,仍需要来源控制、签名或隔离环境来解决。
最后的使用判断
把任务拆成“先看结构、再决定动作”后,选择就很清楚:人眼阅读用 dis,程序筛选用 genops,连续片段才考虑 memo,只有在信任边界已经明确时才考虑恢复对象。对大文件或不熟悉来源的文件,我会先保存反汇编文本和偏移位置,避免把一次排查变成一次不可逆的执行。
常见延伸问题
- 为什么
pickletools.dis看不到原始对象的完整业务结构? 因为它展示的是协议操作码和参数,不负责执行对象构造,也不保证还原出业务层字段关系。 genops返回的pos有什么用? 它对应操作码在 pickle 字节流中的位置,适合把异常或可疑结构定位回原始文件偏移。- 看完反汇编后能直接调用
pickle.loads吗? 只有输入来源、完整性和运行环境都可信时才考虑;反汇编本身不能替代信任判断。
Python types.MappingProxyType 怎样创建只读映射视图
- 上一篇
- Python types.MappingProxyType 怎样创建只读映射视图
- 下一篇
- Python typing.Self 怎样标注链式调用的返回类型
-
- 文章 · python教程 | 20分钟前 |
- Python itertools.islice 怎样截取迭代器而不提前展开
- 383浏览 收藏
-
- 文章 · python教程 | 24分钟前 |
- Python itertools.batched 怎样处理末尾不足一组的数据
- 141浏览 收藏
-
- 文章 · python教程 | 25分钟前 | 标准库 · 调试 · python · Python 装饰器 functools.wraps functools.update_wrapper __wrapped__ inspect.unwrap
- Python functools.update_wrapper 怎样保留装饰器元数据
- 174浏览 收藏
-
- 文章 · python教程 | 44分钟前 |
- Python functools.total_ordering 怎样补齐自定义类的比较方法
- 282浏览 收藏
-
- 文章 · python教程 | 46分钟前 | python · Python 继承 链式调用 类型标注 typing.Self
- Python typing.Self 怎样标注链式调用的返回类型
- 118浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python types.MappingProxyType 怎样创建只读映射视图
- 203浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- Python sqlite3 URI 文件名怎样打开只读数据库
- 218浏览 收藏
-
- 文章 · python教程 | 23小时前 |
- Python tabnanny 怎样定位缩进中混用制表符的问题
- 153浏览 收藏
-
- 文章 · python教程 | 1天前 |
- Python pprint 的sort_dicts怎样影响字典展示顺序
- 326浏览 收藏
-
- 文章 · python教程 | 1天前 |
- Python pprint 怎样控制嵌套对象的展开深度
- 205浏览 收藏
-
- 文章 · python教程 | 1天前 | python · Python graphlib TopologicalSorter
- Python TopologicalSorter 的done为什么必须对应已就绪节点
- 344浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 821次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 814次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 904次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 876次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 696次使用
-
- Python xml.dom.minidom.unlink 怎样释放不再使用的 DOM 树引用
- 2026-10-27 501浏览
-
- Python typing 怎样用 TypeIs 缩小类型
- 2026-10-24 501浏览
-
- Python sqlite3 Connection serialize 怎么导出数据库快照:备份窗口、内存占用与恢复校验
- 2026-08-26 501浏览
-
- Python监控网页状态:requests异常处理实战
- 2026-05-29 501浏览
-
- TensorFlow模型部署为API的TF Serving方法
- 2026-05-26 501浏览

