0
点赞
收藏
分享

微信扫一扫

pickle模块的序列化操作

晒大太阳了 2025-11-15 阅读 360

要理解 pickle模块的作用,核心是先明确它和你之前用的 json 的核心差异——json 是「跨语言、轻量的文本序列化」,而 pickle 是「Python专属、强功能的二进制序列化」,专门解决 json 搞不定的Python特有序列化场景。

一、先一句话回答:pickle 为什么存在?

pickle 是 Python 内置的 二进制序列化模块,核心目的是:把 Python 中任意复杂的对象(比如自定义类实例、函数、列表嵌套字典、循环引用对象等),完整保存到文件/网络中;后续可以再原样恢复(反序列化),连对象的类型、属性、方法都不会丢

它的设计初衷就是「为 Python 量身定做」,解决 json 无法处理的 Python 特有序列化需求。

二、pickle 能做什么?(json 做不到的事)

之前你用 json 序列化 Student 对象,其实需要额外处理(比如 default=lambda obj: obj.__dict__),而且 json 有很多限制。而 pickle 完全不用这些“额外操作”,还能处理更复杂的场景:

1. 直接序列化 Python 自定义类实例(无需转换)

json 序列化 Student 对象需要手动转字典,但 pickle 可以直接dump/load,无需任何额外配置,反序列化后还是原来的 Student 实例(连类的方法都保留):

import pickle

class Student(object):
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score
    
    def get_grade(self):
        return 'A' if self.score >= 90 else 'B'

s = Student('Bob', 20, 88)

# 1. pickle 序列化(直接dump对象,无需转字典)
with open('student.pkl', 'wb') as f:
    pickle.dump(s, f)  # 直接写对象,二进制模式打开文件('wb')

# 2. pickle 反序列化(直接load回Student实例)
with open('student.pkl', 'rb') as f:
    s2 = pickle.load(f)

print(s2.name)  # 输出:Bob(属性保留)
print(s2.get_grade())  # 输出:B(方法也保留)
print(isinstance(s2, Student))  # 输出:True(类型完全一致)

2. 序列化 Python 特有的复杂对象

json 只能序列化简单类型(字符串、数字、列表、字典、布尔值、None),但 pickle 能序列化 Python 中几乎所有对象:

  • 函数/类(比如把一个自定义函数保存到文件,后续加载后直接调用);
  • 复杂数据结构(比如 settuplecollections 模块的 OrderedDictdefaultdict);
  • 循环引用对象(比如 a = [1]; b = [a]; a.append(b),这种循环引用 json 会报错,pickle 能正常处理);
  • 内置对象(比如 datetime.datetime 时间对象、numpy 数组等)。

示例:序列化函数(json 完全做不到)

import pickle

# 定义一个函数
def add(a, b):
    return a + b

# 序列化函数到文件
with open('func.pkl', 'wb') as f:
    pickle.dump(add, f)

# 反序列化后直接调用函数
with open('func.pkl', 'rb') as f:
    add2 = pickle.load(f)

print(add2(3, 5))  # 输出:8(函数功能完全保留)

3. 序列化效率更高、体积更小

pickle二进制格式,而 json 是文本格式:

  • 体积:相同数据,pickle 序列化后的文件大小远小于 json
  • 速度:序列化/反序列化的速度比 json 快(尤其是处理大量数据或复杂对象时)。

三、pickle 的核心特点(和 json 对比)

特性 pickle json
适用场景 Python 内部数据持久化/传输 跨语言数据交换(如前后端、Python<->Java)
支持对象类型 Python 任意对象(类、函数、循环引用等) 仅简单类型(字符串、数字、列表、字典等)
数据格式 二进制(不可读) 文本(人类可读)
跨语言兼容性 无(仅Python可用) 有(所有语言都支持json)
安全性 不安全(加载未知pickle文件可能执行恶意代码) 安全(文本格式,无执行风险)
使用复杂度 低(直接dump/load对象) 中(复杂对象需手动转换)

注意:pickle 不安全!如果加载来自未知来源的 .pkl 文件,可能会执行恶意代码(因为它会还原对象的所有属性和方法,包括恶意逻辑),所以只用来处理「自己生成的、可信的数据」。

四、什么时候用 pickle?什么时候用 json?

用 pickle 的场景:

  1. 你只在 Python 程序之间传输/保存数据(比如 Python 程序的配置、缓存、模型文件,如机器学习训练后的模型 model.pkl);
  2. 需要序列化复杂的 Python 对象(比如自定义类实例、函数、循环引用数据);
  3. 追求序列化速度和文件体积优化。

用 json 的场景:

  1. 需要和其他语言(如 Java、JavaScript、Go)交换数据(比如后端给前端返回数据、接口调用);
  2. 数据需要人类可读(比如配置文件 config.json);
  3. 对数据安全性有要求(避免加载恶意文件)。

五、pickle 基本用法(和 json 很像,但要注意二进制模式)

pickle 的 API 和 json 几乎一致,只是文件操作要用到 二进制模式wb 写、rb 读):

import pickle

# 1. 序列化对象到文件(dump)
obj = {'name': 'Bob', 'age': 20, 'scores': [88, 92]}
with open('data.pkl', 'wb') as f:
    pickle.dump(obj, f)  # 二进制写

# 2. 从文件反序列化(load)
with open('data.pkl', 'rb') as f:
    obj2 = pickle.load(f)  # 二进制读
print(obj2)  # {'name': 'Bob', 'age': 20, 'scores': [88, 92]}

# 3. 序列化到内存字节串(dumps)
byte_data = pickle.dumps(obj)
print(type(byte_data))  # <class 'bytes'>(二进制类型)

# 4. 从内存字节串反序列化(loads)
obj3 = pickle.loads(byte_data)
print(obj3 == obj)  # True

总结

pickle 的存在,是为了满足 Python 专属的「复杂对象序列化需求」——它放弃了跨语言兼容性和可读性,换来了对 Python 对象的完全支持、更高的效率和更小的体积。

简单说:跨语言/可读用 json,Python 内部复杂对象序列化用 pickle

举报
0 条评论