如何利用Python pickle模块实现Python对象的深度持久化存储?

秋涛同学_7460

秋涛同学_7460

2026-06-24

352人浏览

原创

pickle天然支持深度持久化,因其默认跟踪对象引用、处理嵌套结构、循环引用、递归及自定义类实例,能完整封存并重建对象图,但不保证跨版本兼容且存在安全风险。

如何利用python pickle模块实现python对象的深度持久化存储?

pickle 能做到深度持久化——但不是靠“加参数”,而是靠它默认就支持嵌套、引用、递归和自定义类实例。只要你没手动破坏对象图结构,它就能原样存、原样读回来。

为什么 pickle.dump() 和 pickle.load() 天然支持深度序列化

pickle 的核心机制是跟踪对象引用,不是简单地 flatten 字段。比如一个包含循环引用的树节点、一个带方法绑定的实例、或者字典里嵌套了 set 再嵌套了自定义对象——只要这些对象在 Python 运行时可被访问(即类定义在模块里可 import),pickle 就能完整封存整个对象图。
  • 它会自动处理 list 里套 dict 套 set 套 datetime 套自定义类实例
  • 对同一对象的多次引用(如 a = [obj, obj])不会重复序列化,解封后仍是同一内存地址(is 成立)
  • 递归结构(如 node.parent = node)也能安全封存,不会栈溢出或崩溃

注意:pickle 不保存对象的内存地址,而是重建等价结构;反序列化后的对象与原对象 == 成立,但 is 不成立(除非你用 copy.deepcopy 那种语义,而它本来就是 deep copy 行为)。

pickle.dumps() 和 pickle.loads() 在内存中做深度序列化的实操要点

这两个函数适合缓存、RPC、进程间通信等不落地场景,但容易因忽略协议版本或编码方式出错:
  • pickle.dumps(obj) 默认用 protocol=3(Python 3.8+),但如果你要兼容旧环境(比如 Python 3.6),显式传 protocol=4 可能反而失败——protocol=4 是 3.8+ 才支持的
  • 返回值一定是 bytes,别试图用 str 处理或写入文本文件
  • pickle.loads() 输入必须是 bytes,传 str 会报 TypeError: a bytes-like object is required
  • 如果对象含不可序列化成分(比如 lambda、打开的文件句柄、线程锁),dumps() 会直接抛 AttributeError 或 PicklingError

常见错误示例:

python 查询技能
python 查询技能

查询客流数据,输出JSON格式,可直接导入Bitable等可视化工具

下载
import pickle
obj = {'data': lambda x: x * 2}
pickle.dumps(obj)  # 报错:Can't pickle <function> at 0x...></function>

自定义类如何确保深度持久化不丢状态

默认情况下,pickle 会保存实例的 __dict__,但如果你重写了 __slots__、用了属性描述符、或有非 __dict__ 存储的状态(比如 C 扩展对象),就得手动干预:
  • 重写 <strong>getstate</strong>():返回你想持久化的状态字典(比如过滤掉临时计算字段)
  • 重写 <strong>setstate</strong>():从字典恢复实例状态,必要时初始化未序列化的属性
  • 若类依赖外部模块或动态生成,确保反序列化时该模块仍可导入(否则 ModuleNotFoundError)

典型场景:

  • 机器学习模型训练完想保存权重和配置,但不想存 optimizer 状态 → 在 __getstate__ 里 pop 掉 'optimizer'
  • 某个类用 __slots__ 节省内存 → 必须在 __getstate__ 中显式构造状态字典,否则 __dict__ 为空导致数据丢失

深度持久化的最大陷阱:跨 Python 版本和不可信数据

深度 ≠ 安全,也不等于长期兼容:
  • pickle 协议不保证跨大版本兼容(比如 Python 3.9 dump 的数据,在 3.12 load 可能失败),尤其涉及内置类型内部变更(如 dict 实现优化)
  • 反序列化任意 bytes 等同于执行任意代码——攻击者可以构造恶意 payload,在 pickle.load() 时触发 os.system() 或远程加载模块
  • 生产环境绝对不要对用户上传的 .pkl 文件、网络接收的 bytes 直接调用 loads()

真正需要深度持久化的场景,往往也意味着你控制着序列化和反序列化两端。这时候,把协议版本写死、加一层 hmac 签名校验、并限定只允许特定类名被反序列化,比幻想“一次封存,永久可用”更实际。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1731

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4424

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1709

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

25977

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3147

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3167

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1183

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2463

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习