0

0

Python怎么序列化一个对象(pickle)_pickle模块对象序列化与反序列化

裘德小鎮的故事

裘德小鎮的故事

发布时间:2025-09-12 14:02:01

|

350人浏览过

|

来源于php中文网

原创

pickle模块用于Python对象的序列化与反序列化,支持复杂对象类型,但仅限于可信环境使用,因反序列化不可信数据可能导致任意代码执行;推荐在纯Python、跨语言需求低且数据源可信的场景中使用,否则应选用JSON等更安全的替代方案。

python怎么序列化一个对象(pickle)_pickle模块对象序列化与反序列化

Python的

pickle
模块提供了一种将Python对象序列化(即转换为字节流)和反序列化(即从字节流恢复为Python对象)的机制。这在需要持久化对象、在不同进程间传递对象或通过网络传输对象时非常有用。简单来说,它能把你的Python数据结构“冻结”成一串字节,然后随时“解冻”回来。

解决方案

使用

pickle
模块进行对象的序列化与反序列化,主要涉及
dump/load
dumps/loads
两对函数。

当你需要将一个Python对象保存到文件(或任何文件状对象)时,可以使用

pickle.dump()
。它接收两个参数:要序列化的对象和文件对象。

import pickle

data = {
    'name': '张三',
    'age': 30,
    'city': '北京',
    'scores': [95, 88, 92]
}

# 序列化到文件
try:
    with open('my_data.pkl', 'wb') as f: # 注意这里是'wb',写入二进制模式
        pickle.dump(data, f)
    print("数据已成功序列化并保存到 my_data.pkl")
except Exception as e:
    print(f"序列化失败: {e}")

# 从文件反序列化
try:
    with open('my_data.pkl', 'rb') as f: # 注意这里是'rb',读取二进制模式
        loaded_data = pickle.load(f)
    print("数据已成功从 my_data.pkl 反序列化:")
    print(loaded_data)
except FileNotFoundError:
    print("文件 my_data.pkl 不存在。")
except Exception as e:
    print(f"反序列化失败: {e}")

如果你的需求是把对象序列化成一个字节字符串,而不是直接写入文件,那么

pickle.dumps()
就派上用场了。它只接收一个参数:要序列化的对象,然后返回一个字节串。对应的反序列化函数是
pickle.loads()
,它接收一个字节串并返回原始的Python对象。

立即学习Python免费学习笔记(深入)”;

import pickle

class MyObject:
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return f"MyObject(value={self.value})"

obj = MyObject(123)
another_data = {'id': 1, 'object': obj}

# 序列化为字节串
pickled_bytes = pickle.dumps(another_data)
print(f"序列化后的字节串: {pickled_bytes}")

# 从字节串反序列化
unpickled_data = pickle.loads(pickled_bytes)
print(f"反序列化后的数据: {unpickled_data}")
print(f"反序列化后的对象类型: {type(unpickled_data['object'])}")
print(f"反序列化后的对象值: {unpickled_data['object'].value}")

pickle
模块的安全性如何?使用时需要注意哪些风险?

谈到

pickle
,安全性是一个绕不开的话题,而且通常是排在首位的注意事项。我的个人经验是,如果你不了解其潜在风险,最好不要在处理不可信数据时使用它。
pickle
模块在设计上,并没有考虑对抗恶意构造的数据。这意味着,如果你反序列化一个由攻击者精心构造的字节流,它可能会在你的系统上执行任意代码。这可不是开玩笑的,它能直接导致严重的安全漏洞。

为什么会这样呢?因为

pickle
在反序列化时,实际上会执行一些操作来重建Python对象,包括调用类的方法、构造函数等。如果这些操作被恶意利用,就能触发代码执行。举个例子,一个攻击者可以构造一个字节流,使得在反序列化时,它会导入一个系统模块,然后调用一个危险的函数,比如删除文件或者执行shell命令。

所以,我的建议是:永远不要反序列化来自不可信源的

pickle
数据。如果你确实需要处理外部数据,但又无法保证其来源的绝对安全,那么
pickle
就不是你的首选。在这种情况下,更安全的替代方案是使用JSON、YAML或Protocol Buffers等跨语言的序列化格式。这些格式通常只允许表示基本数据类型(字符串、数字、列表、字典等),不会涉及代码执行,因此安全性更高。当然,它们也有各自的限制,比如不能直接序列化复杂的Python对象,需要手动进行转换。但为了安全,这点额外的开发工作是值得的。

如何序列化自定义类或复杂对象?
pickle
在处理这些情况时有什么限制?

pickle
模块在处理自定义类和复杂对象方面,确实展现了其强大之处。它通常能够“开箱即用”地序列化大多数Python对象,包括自定义类的实例。这得益于
pickle
能够保存对象的类信息以及其状态(实例属性)。当反序列化时,
pickle
会找到对应的类定义,然后根据保存的状态重新创建对象。

然而,这并不是没有限制的。最常见的一个限制是,在反序列化时,自定义类的定义必须在当前环境中可用。也就是说,如果你序列化了一个

MyClass
的实例,那么在进行反序列化的程序中,
MyClass
的定义(所在的模块和代码)必须能够被Python找到。如果找不到,就会抛出
AttributeError
ModuleNotFoundError
。这对于在同一应用的不同部分或同一台机器上的不同进程间传递对象通常不是问题,但如果跨版本、跨环境,或者类定义发生了变化,就可能遇到麻烦。

另外,有些Python对象是无法被

pickle
序列化的。这包括:

LongShot
LongShot

LongShot 是一款 AI 写作助手,可帮助您生成针对搜索引擎优化的内容博客。

下载
  • 文件句柄、网络连接、数据库连接:这些是与操作系统资源绑定的对象,无法直接序列化其状态。
  • 匿名函数(lambda)和嵌套函数
    pickle
    通常无法可靠地序列化这些。
  • 线程锁、信号量等同步原语:这些也与运行时状态紧密相关。
  • 一些特殊的内置类型或C扩展对象:它们可能没有实现
    pickle
    协议。

对于这些无法直接序列化的对象,或者当你需要对序列化过程进行更精细的控制时,

pickle
提供了一些“魔术方法”:
__getstate__
__setstate__

  • __getstate__(self)
    :这个方法应该返回一个代表对象状态的对象,这个对象是可序列化的。
    pickle
    会序列化这个返回值而不是对象的
    __dict__
  • __setstate__(self, state)
    :这个方法在反序列化时被调用,接收
    __getstate__
    返回的状态对象,然后用它来恢复对象的状态。

通过这两个方法,你可以自定义哪些数据需要被序列化,以及如何重建对象。例如,你可以选择不序列化一个文件句柄,而只保存其路径,然后在

__setstate__
中重新打开文件。

import pickle

class MyResource:
    def __init__(self, filename):
        self.filename = filename
        self.file_handle = open(filename, 'w') # 模拟一个不可序列化的资源
        self.file_handle.write("Initial content\n")

    def __getstate__(self):
        # 返回一个可序列化的状态,这里只保存文件名
        state = {'filename': self.filename}
        return state

    def __setstate__(self, state):
        # 从状态中恢复对象,重新打开文件
        self.filename = state['filename']
        self.file_handle = open(self.filename, 'a') # 以追加模式重新打开
        print(f"资源 {self.filename} 已重新打开。")

    def write_data(self, data):
        self.file_handle.write(data + '\n')

    def close(self):
        self.file_handle.close()
        print(f"资源 {self.filename} 已关闭。")

# 创建并序列化对象
resource_obj = MyResource('temp_log.txt')
resource_obj.write_data("First line.")
resource_obj.close() # 序列化前关闭文件,避免问题

pickled_resource = pickle.dumps(resource_obj)

# 反序列化对象
unpickled_resource = pickle.loads(pickled_resource)
unpickled_resource.write_data("Second line after unpickling.")
unpickled_resource.close()

# 清理
import os
os.remove('temp_log.txt')

这个例子展示了如何通过

__getstate__
__setstate__
来处理一个包含文件句柄这种不可序列化资源的自定义类。

pickle
与其他序列化方法(如JSON、msgpack)有何不同?何时选择
pickle

pickle
、JSON和msgpack都是常见的序列化工具,但它们各有侧重,适用于不同的场景。理解它们之间的差异,能帮助我们做出更明智的选择。

pickle

  • Python特有:它是Python语言专用的序列化格式,这意味着序列化后的数据只能被Python程序反序列化。
  • 二进制格式:序列化结果是二进制字节流,通常比文本格式更紧凑。
  • 功能强大:能够序列化几乎所有Python对象,包括自定义类实例、函数、甚至模块(尽管这通常不推荐,且有安全风险)。它能保留Python对象的完整结构和类型信息。
  • 安全性低:如前所述,不应反序列化不可信数据。

JSON (JavaScript Object Notation):

  • 跨语言:JSON是一种语言无关的文本格式,被几乎所有主流编程语言支持。
  • 文本格式:人类可读,易于调试。
  • 数据类型有限:主要支持基本数据类型:字符串、数字、布尔值、列表、字典、null。无法直接表示Python的元组、集合、日期时间对象或自定义类实例。需要手动进行转换。
  • 安全性高:由于只处理数据,不涉及代码执行,因此相对安全。

msgpack:

  • 跨语言:与JSON类似,msgpack也是一种跨语言的二进制序列化格式。
  • 二进制格式:比JSON更紧凑,解析速度通常更快。
  • 数据类型比JSON略多:支持JSON的基本类型,并能更高效地处理二进制数据。
  • 安全性高:同样不涉及代码执行,安全性良好。

何时选择

pickle

我的经验是,

pickle
的最佳使用场景是在受信任的环境中,进行Python程序内部或Python程序之间的对象持久化和通信。具体来说:

  1. 进程间通信 (IPC):当你在同一个系统上运行多个Python进程,并且需要高效地传递复杂的Python对象时,
    pickle
    是一个很好的选择。例如,使用
    multiprocessing
    模块时,它在幕后就使用了
    pickle
  2. 对象持久化:将Python对象保存到磁盘,以便稍后由同一个Python程序(或兼容版本的Python程序)加载和恢复。这对于缓存计算结果、保存程序状态等非常有用。
  3. 需要保留Python对象完整性:如果你的对象包含复杂的结构,比如自定义类的实例、函数引用、集合、元组等,并且你希望在反序列化后完全恢复这些对象的原始类型和结构,那么
    pickle
    是首选,因为它能做到这一点而无需额外的类型映射或转换。
  4. 性能要求较高,且数据源可信:在Python内部,
    pickle
    通常比JSON等文本格式有更好的序列化和反序列化性能,因为它不需要进行文本解析和数据类型转换。

总结一下,如果你的应用场景是纯Python环境,且数据来源绝对可信,同时你需要处理复杂且多样化的Python对象,那么

pickle
无疑是最方便和强大的选择。但一旦涉及跨语言、不确定数据来源或对数据格式有严格要求(如Web API),那么JSON或msgpack会是更稳妥、更通用的方案。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

769

2023.06.15

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

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

661

2023.07.20

python能做什么
python能做什么

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

764

2023.07.25

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

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

659

2023.07.31

python教程
python教程

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

1345

2023.08.03

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

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

549

2023.08.04

python eval
python eval

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

579

2023.08.04

scratch和python区别
scratch和python区别

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

730

2023.08.11

html编辑相关教程合集
html编辑相关教程合集

本专题整合了html编辑相关教程合集,阅读专题下面的文章了解更多详细内容。

37

2026.01.21

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.9万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.4万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号