news 2026/2/26 12:55:40

Python 对象序列化与存储库pickle详细介绍

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 对象序列化与存储库pickle详细介绍

一、pickle 是什么?

pickle是 Python 标准库中的对象序列化工具

  • 序列化(dumping / pickling):把内存中的 Python 对象(如列表、字典、自定义类实例等)转换成字节流(bytes),以便:
    • 写入文件
    • 通过网络发送
    • 存入缓存或数据库的二进制字段等
  • 反序列化(loading / unpickling):把字节流重新还原为原先的 Python 对象。

特点:

  • 支持大多数内置类型和自定义类实例。
  • 是 Python 专用的二进制协议,不同语言之间不通用
  • 默认协议不是可读文本(不是 JSON / YAML,而是二进制格式)。

适用场景:在 Python 环境内部保存/恢复复杂对象(如机器学习模型、缓存的中间结果、复杂数据结构等)。


二、基本接口与常用函数

1. 常用函数

importpickle# 写入/读取文件接口pickle.dump(obj,file,protocol=None)# 序列化到文件对象pickle.load(file)# 从文件对象反序列化# 操作 bytes 接口pickle.dumps(obj,protocol=None)# 序列化为 bytespickle.loads(data)# 从 bytes 反序列化
  • protocol:序列化协议版本,整数,一般用:
    • protocol=pickle.HIGHEST_PROTOCOL(推荐)
    • 不写时使用默认协议(不同 Python 版本默认值不同)

三、基础用法示例

1. 序列化到文件 / 从文件加载

importpickle data={"name":"Alice","age":25,"scores":[95,88,76],"active":True}# 写入文件(推荐使用二进制模式 'wb')withopen("data.pkl","wb")asf:pickle.dump(data,f,protocol=pickle.HIGHEST_PROTOCOL)# 从文件读取withopen("data.pkl","rb")asf:loaded_data=pickle.load(f)print(loaded_data)

说明:

  • 文件扩展名通常用.pkl.pickle.p,仅是约定,非强制。
  • 必须使用二进制模式"wb"/"rb"

2. 转换为 bytes / 从 bytes 恢复

importpickle obj=[1,2,3,{"a":10}]data_bytes=pickle.dumps(obj,protocol=pickle.HIGHEST_PROTOCOL)# 可以用于网络传输、缓存等restored=pickle.loads(data_bytes)print(restored)

四、pickle 支持哪些类型?

大多数常见类型都支持:

  • 基本类型:intfloatboolstrbytesNone
  • 容器类型:listtupledictsetfrozenset
  • 函数、类、实例(有一些限制,见后文)
  • datetimedecimal.Decimalfractions.Fraction等常用内置类型
  • 许多第三方库对象(如大部分sklearn模型)——库作者实现了对应的序列化协议

不太适合 / 有限制的对象:

  • 打开的文件对象、数据库连接、线程、进程、锁等与系统资源强绑定的对象:
    • 常常无法完全恢复原状态(反序列化时环境已不同)
  • lambda 匿名函数、内部函数、局部类等:普通pickle不能可靠处理(要用dill等扩展库)

五、pickle 协议(protocol)版本

protocol是决定如何编码对象为字节流的“格式版本”。

  • 常用写法:
    pickle.dump(obj,f,protocol=pickle.HIGHEST_PROTOCOL)
  • 查看当前解释器支持的最高协议:
    importpickleprint(pickle.HIGHEST_PROTOCOL)
  • 越新的协议:
    • 通常更高效、更紧凑
    • 但在旧版本 Python 上可能无法反序列化

跨 Python 版本使用 Pickle 时:

  • 如果你需要在不同 Python 版本间共享.pkl文件,建议:
    • 较低版本的 Python 中查看HIGHEST_PROTOCOL,然后在较高版本中固定使用该协议版本。
    • 或者使用更兼容的格式(如 JSON、msgpack 等)。

六、自定义类的 pickle 行为

1. 直接序列化自定义类实例

默认情况下,自定义类的实例是可以被 pickle 的:

importpickleclassPerson:def__init__(self,name,age):self.name=name self.age=age p=Person("Alice",25)# 序列化data=pickle.dumps(p)# 反序列化p2=pickle.loads(data)print(p2.name,p2.age)

要求:

  • 类定义在模块的顶层作用域(不是函数内部)。
  • 反序列化时,需要能找到同名模块和类定义,否则会失败:
    • 也就是说:Person类定义在mymodule.py中,那么加载 pickle 时环境里也要有mymodule.Person

2. 控制属性:__getstate____setstate__

如果你想:

  • 某些属性不参与序列化(如打开的文件句柄)
  • 序列化前/后做一些处理

可以在类中实现:

classPerson:def__init__(self,name,age,temp_file=None):self.name=name self.age=age self.temp_file=temp_file# 不打算序列化这个属性def__getstate__(self):# 返回要被序列化的“状态”字典state=self.__dict__.copy()# 删除不希望被序列化的属性if'temp_file'instate:delstate['temp_file']returnstatedef__setstate__(self,state):# 从状态恢复实例self.__dict__.update(state)# 反序列化后,可赋默认值或重新构造资源self.temp_file=None

说明:

  • __getstate__返回任何可被 pickle 序列化的对象(通常是 dict)。
  • __setstate__(state)用来根据序列化得到的state恢复对象内部状态。

3. 更底层的控制:__reduce__/__reduce_ex__

当序列化某个对象时,pickle会调用:

  • obj.__reduce_ex__(protocol)(如存在)
  • 否则调用obj.__reduce__()

它们需要返回一种描述如何重新构造该对象的信息,一般形式是一个 2~5 元组,常见形式:

(callable,args,state)

示例(简单展示用法,不必死记):

classMyClass:def__init__(self,value):self.value=value self.cache=value*2# 想在恢复时重新计算def__reduce__(self):# 用 MyClass 构造函数和一个参数创建实例reconstruct_callable=self.__class__ reconstruct_args=(self.value,)# state 用于存其他信息,这里暂时用 Nonestate=Nonereturn(reconstruct_callable,reconstruct_args,state)def__setstate__(self,state):# 反序列化后,重新构造 cacheself.cache=self.value*2

平时多数情况下只用__getstate__/__setstate__即可,__reduce__适合高级定制或 C 扩展类。


七、处理大型对象与性能优化

1. 使用最高协议 & 二进制 I/O

pickle.dump(obj,f,protocol=pickle.HIGHEST_PROTOCOL)

优点:

  • 通常速度更快
  • 文件更小

2. 使用protocol >= 4的大对象支持

  • 新协议对大对象(>4GB)支持更好。
  • Python 3.8+ 中的默认协议已足够。

3. 对于多对象序列化

若你想把多个对象“顺序写入”同一个文件:

withopen("multi.pkl","wb")asf:pickle.dump(obj1,f,protocol=pickle.HIGHEST_PROTOCOL)pickle.dump(obj2,f,protocol=pickle.HIGHEST_PROTOCOL)withopen("multi.pkl","rb")asf:a=pickle.load(f)b=pickle.load(f)

注意:

  • 加载时需要按相同顺序多次调用pickle.load
  • 不可随机访问中间对象(除非自己管理偏移量)。

如果要实现可随机访问的“对象仓库”,可考虑:

  • shelve模块(基于 pickle + dbm)
  • 或自己实现索引(对象位置表 + seek)

八、安全性:务必注意反序列化风险

这是使用 pickle 时最重要的问题。

1. pickle 反序列化是不安全的

官方文档明确说明:
不可信数据调用pickle.loadpickle.loads危险的,可能导致代码执行、系统被攻陷。

原因:

  • pickle协议中可以编码“调用任意可导入对象”的指令。
  • 恶意构造的 pickle 字节流可以在加载时触发执行任意 Python 代码(RCE)。

总结一句话:

只有在完全信任数据来源的前提下,才能使用pickle.load/pickle.loads

2. 安全使用建议

  • 绝对不要对以下来源的数据使用pickle.loads

    • 用户上传的文件 / 表单
    • 网络请求中的数据(HTTP body / WebSocket 等)
    • 来历不明的.pkl文件
  • 如果必须支持某种持久化格式给外部使用,建议:

    • 使用 JSON、MessagePack、Protocol Buffers、Avro 等更安全和跨语言的序列化格式。
    • 或自行设计清晰受限的数据结构(比如只允许 dict/list/str/int 等基本类型)。
  • 在内部(可信环境)用 pickle:

    • 仅在团队内部、受控环境下使用.pkl共享数据。
    • 若部署在可能暴露接口的服务中,不要直接接受外部传来的 pickled 数据。

九、实际例子:缓存结果到硬盘

示例:耗时计算结果缓存到本地,下次直接读取。

importosimportpickle CACHE_FILE="result_cache.pkl"defheavy_compute():# 模拟耗时操作fromtimeimportsleep sleep(3)return{"result":42,"detail":[1,2,3]}defget_result():ifos.path.exists(CACHE_FILE):withopen(CACHE_FILE,"rb")asf:returnpickle.load(f)res=heavy_compute()withopen(CACHE_FILE,"wb")asf:pickle.dump(res,f,protocol=pickle.HIGHEST_PROTOCOL)returnresif__name__=="__main__":print("First call:")print(get_result())print("Second call (should be faster):")print(get_result())

十、与其它序列化方式的比较(简要)

方式格式可读性跨语言支持复杂 Python 对象安全(默认)典型用途
pickle二进制否(危险)Python 内部的对象持久化
JSON文本限制多(基本类型为主)相对安全简单配置、Web 接口、跨语言
msgpack二进制一般相对安全高效跨语言序列化
protobuf二进制用 schema 定义结构相对安全大规模服务间通信、强类型约束

结论:

  • 只在 Python 内部,且数据来源可信:用pickle很方便,支持自定义类。
  • 需要跨语言或不完全可信数据源:优先考虑 JSON / msgpack / protobuf 等。

十一、小结与使用建议

  1. 基本用法:
    • pickle.dump(obj, f)/pickle.load(f)处理文件;
    • pickle.dumps(obj)/pickle.loads(bytes)处理内存中的 bytes。
  2. 对自定义类:
    • 顶层定义类,反序列化时保持类可导入;
    • 可以用__getstate__/__setstate__精细控制。
  3. 性能:
    • protocol=pickle.HIGHEST_PROTOCOL
    • 注意版本兼容问题。
  4. 安全:
    • 永远不要反序列化不可信来源的 pickle 数据
    • 对外部接口应使用更安全、跨语言的格式。
  5. 场景典型用途:
    • Python 项目内部的模型、缓存、中间结果持久化;
    • 一次性脚本、实验性数据保存。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/14 20:11:06

鸿蒙 Electron 跨生态协同:与 Windows/macOS/Android 互联互通实战

鸿蒙Electron跨生态协同:与Windows/macOS/Android互联互通实战 在多系统并存的办公与生活场景中,单一设备的能力边界始终有限。鸿蒙Electron凭借鸿蒙系统的分布式软总线技术,打破了Windows、macOS、Android与鸿蒙设备之间的壁垒,…

作者头像 李华
网站建设 2026/2/20 11:42:44

Manus与LangChain智能体实战经验!DeepMind工程师的上下文工程哲学

随着大模型能力的边界不断拓展,我们构建智能体的方式正在经历一场静悄悄却剧烈的范式转移,核心不再是堆砌更复杂的提示词,而是学会如何优雅地让路。Google DeepMind 工程师 Philipp Schmid,总结了 Manus 创始人 Peak Ji&#xff0…

作者头像 李华
网站建设 2026/2/24 11:51:21

鸿蒙应用交互设计:实现流畅的页面跳转与状态管理

鸿蒙应用交互设计:实现流畅的页面跳转与状态管理 一、章节概述 ✅ 学习目标 掌握鸿蒙应用页面跳转的完整流程熟练使用 AbilitySlice 与 Page 进行页面管理理解并应用多种状态管理方案实现页面间的数据传递与回调构建流畅的用户交互体验 💡 重点内容 Abil…

作者头像 李华
网站建设 2026/2/25 9:16:41

esmini完整指南:10分钟学会开源自动驾驶仿真

esmini完整指南:10分钟学会开源自动驾驶仿真 【免费下载链接】esmini a basic OpenSCENARIO player 项目地址: https://gitcode.com/gh_mirrors/es/esmini 在当今自动驾驶技术快速发展的时代,一个高效且易于使用的仿真平台对于开发者和研究者来说…

作者头像 李华
网站建设 2026/2/18 9:55:29

终极指南:如何使用Dlib构建完整的疲劳驾驶检测系统

终极指南:如何使用Dlib构建完整的疲劳驾驶检测系统 【免费下载链接】Fatigue-Driving-Detection-Based-on-Dlib 项目地址: https://gitcode.com/gh_mirrors/fa/Fatigue-Driving-Detection-Based-on-Dlib 在当今交通安全日益重要的背景下,Dlib疲劳…

作者头像 李华