Python序列化与反序列化详解:JSON与Pickle对比及多次序列化问题

Miles
Miles
发布时间:2026-10-14 | 6人浏览过
原创

本文深入解析Python中对象序列化的两种核心方式:JSON与Pickle。详细对比了json.dumps/loads与pickle.dumps/loads在数据类型支持、文件读写模式及函数序列化能力上的差异,重点探讨了多次序列化同一对象到文件时JSON与Pickle的不同表现及反序列化报错原因,为Python数据持久化提供实用指南。

序列化基本概念

序列化是指将内存中的对象状态转换为可存储或传输格式的过程。在此过程中,对象将其当前状态写入临时或持久性存储区(如硬盘)。随后,可以通过从存储区读取并进行反序列化,重新构建该对象。

Python序列化方式概述

在Python中,实现对象的序列化和反序列化主要有两种途径:json模块和pickle模块。

其中,json主要用于字符串与Python基本数据类型之间的相互转换;而pickle则专门用于Python特有数据类型与标准数据类型之间的转换,它是Python语言特有的序列化机制。

JSON序列化与反序列化详解

首先介绍JSON序列化方法:json.dumps()。该方法将Python对象转换为JSON格式的字符串。


info = {
  "name":"tj",
  "age":22
}
import json
print(info)
print(type(info))
print(json.dumps(info))
print(type(json.dumps(info)))

f = open("test.txt","w")
# f.write(info)  # TypeError: write() argument must be str, not dict
f.write(json.dumps(info)) # 正常写入文件 f.write(json.dumps(info)) 等价于 json.dump(info, f)
f.close()

>>>
{'name': 'tj', 'age': 22}
<class 'dict'>
{"name": "tj", "age": 22}
<class 'str'>

接着是JSON反序列化方法:json.loads()。该方法将JSON格式的字符串还原为Python对象。


f = open("test.txt","r")
# print(f.read()["age"]) #TypeError: string indices must be integers
data = json.loads(f.read()) # data = json.loads(f.read()) 等价于 data = json.load(f)
print(data["age"])
f.close()

>>>
22

需要注意的是,对于包含函数等复杂类型的对象,JSON无法直接处理。

JSON处理函数的局限性


import json
def hello(name):
  print("hello,",name)
info = {
  "name":"tj",
  "age":22,
  "func":hello
}
f = open("test2.txt","w")
f.write(json.dumps(info)) #TypeError: Object of type function is not JSON serializable
f.close()

因此,JSON仅适用于字符串与Python基本数据类型之间的转换场景。

Pickle序列化与反序列化详解

接下来介绍pickle序列化方法:pickle.dumps()。该方法将Python对象转换为字节流。


import pickle
def hello(name):
  print("hello,",name)
info = {
  "name":"tj",
  "age":22,
  "func":hello
}

print(pickle.dumps(info)) #可见pickle序列化的结果输出为二进制,所以应使用wb的方式往文件中写
f = open("test2.txt","wb")
f.write(pickle.dumps(info)) # 等价于 pickle.dump(info,f)
f.close()

>>>
b'\x80\x04\x957\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x04alex\x94\x8c\x03age\x94K\x16\x8c\x04func\x94\x8c\x08__main__\x94\x8c\x05hello\x94\x93\x94u.'

对于函数对象,序列化保存的是整个数据对象而非内存地址,因此函数本身可以被pickle序列化。

对应的pickle反序列化方法为:pickle.loads()。该方法将字节流还原为Python对象。

Pickle对函数的序列化支持


f = open("test2.txt","rb")
data = pickle.loads(f.read()) # 等价于data = pickle.load(f)
print(data)
print(data["name"])
print(data["func"])

>>>
{'name': 'tj', 'age': 22, 'func': <function hello at 0x00000179EF69C040>}
tj
<function hello at 0x00000179EF69C040>

多次序列化与反序列化的处理

此外,还需要关注多次序列化与反序列化的情况。

第一种情况是使用JSON进行多次序列化。

JSON多次序列化的反序列化问题


import json
info = {
  "name":"tj",
  "age":22
}

f = open("test3.txt","w")
f.write(json.dumps(info))
info['age'] = 21
f.write(json.dumps(info))
f.close()
# 
>>>
序列化两次后test3中的内容
test3.txt: {"name": "tj", "age": 22}{"name": "tj", "age": 21}

f = open("test3.txt","r")
# 报错,py3以上,多次dumps的文件反序列化报错,py2多次dumps的文件也能被反序列化,先序列化的先被反序列化
data = json.loads(f.read()) # json.decoder.JSONDecodeError
f.close()
print(data)

第二种情况是使用Pickle进行多次序列化。

Pickle多次序列化的反序列化行为


import pickle

info = {
  "name":"tj",
  "age":22
}

f = open("test2.txt","wb")
f.write(pickle.dumps(info)) # 等价于 pickle.dump(info,f)
info["sex"] = "女"
f.write(pickle.dumps(info)) # 等价于 pickle.dump(info,f)
f.close()

>>>
序列化两次后test2.txt中的内容
test2.txt: ��    }�(�name攲tj攲age擪u.��%    }�(�name攲tj攲age擪�sex攲濂硵u.

f = open("test2.txt","rb")
data = pickle.loads(f.read()) # 第一次反序列化正常
# data = pickle.loads(f.read()) # 第二次反序列化:EOFError: Ran out of input
print(data)
print(data["age"])
# print(data["sex"]) # KeyError: 'sex'

有人可能会问:是否就不能进行多次序列化?如果修改了数据,该如何将其序列化并写入文件?

当然可以进行多次序列化,只需将每次序列化后的数据写入不同的文件即可解决。

以上是对Python序列化与反序列化的简要分析,更多相关技术细节请查阅本站其他文章。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表