Python序列化与反序列化详解:JSON与Pickle对比及多次序列化问题
本文深入解析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序列化与反序列化的简要分析,更多相关技术细节请查阅本站其他文章。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













