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

裘德小鎮的故事
发布: 2025-09-12 14:02:01
原创
331人浏览过
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
登录后复制
序列化的。这包括:

序列猴子开放平台
序列猴子开放平台

具有长序列、多模态、单模型、大数据等特点的超大规模语言模型

序列猴子开放平台 0
查看详情 序列猴子开放平台
  • 文件句柄、网络连接、数据库连接:这些是与操作系统资源绑定的对象,无法直接序列化其状态。
  • 匿名函数(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怎么序列化一个对象(pickle)_pickle模块对象序列化与反序列化的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

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