我们把变量从内存中变成可存储或传输的过程(字节序列-一串二进制数据的序列)称之为序列化,在Python中叫pickling,序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。

因为计算机只能存储二进制的数据,所以要想把一些内存存到计算机上,必须将其编码成二进制的序列(字节数组),然后读取的时候进行相应解码(如ascii、Unicode等),将其转为原始的数据进行显示。
而且一些传输协议,例如TCP/IP协议,只支持字节数组的传输,不能直接传对象。对象序列化的结果一定是字节数组!当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为对象。

目录

  • 1.python中pickle的序列化与反序列化
    • 1.1把一个对象序列化并写入文件
    • 1.2.从文件中读取字节序列进行反序列化
  • 2.python利用json包的序列化与反序列化
    • 2.1 json的序列化与反序列化——python内置的数据类型
      • 2.1.1 把Python对象变成一个JSON并写入文件
      • 2.1.1 从文件中读取json数据进行反序列化
    • 2.2.json的序列化与反序列化——其他的对象
      • 2.2.1 自定义default转换函数,把其他的对象变成一个JSON并写入文件
      • 2.2.2 自定义object_hook转换函数,从文件中读取json数据进行反序列化为自定义的对象
      • 2.2.3 创建一个类,继承json.JSONEncoder,重写default方法进而实现序列化
      • 2.2.3 创建一个类,继承json.JSONDecoder,重写decode方法进而实现反序列化
  • 3. 综合的例子

1.python中pickle的序列化与反序列化

Python提供了pickle模块来实现序列化。

1.1把一个对象序列化并写入文件

pickle.dumps()方法把对象序列化成一个bytes,然后,就可以把这个bytes写入文件。

import pickle
d = dict(name='Bob', age=20, score=88)# 序列化为字节数组
d_pickling = pickle.dumps(d)# 将序列化的字节数组写入pickling.txt
with open('pickling.txt', 'wb') as output:output.write(d_pickling)# 将pickling.txt中存放的序列化的字节数组读入
with open('pickling2.txt', 'rb') as f:d_pickling = f.read()
print(d_pickling)


或者用另一个方法pickle.dump()直接把对象序列化后写入一个file-like Object

import pickle
d = dict(name='Bob', age=20, score=88)# 将对象序列化后的二进制数组存入pickling.txt
with open('pickling.txt', 'wb') as f:pickle.dump(d, f)# 将pickling.txt的内容读取出来
with open('pickling.txt', 'rb') as f:d_pickling = f.read()
print(d_pickling)

1.2.从文件中读取字节序列进行反序列化

当我们要把对象从磁盘读到内存时,可以先把内容读到一个bytes,然后用pickle.loads()方法反序列化出对象,也可以直接用pickle.load()方法从一个file-like Object中直接反序列化出对象。
使用pickle.loads()方法

# 对d_pickling字节序列直接反序列化
print(d_pickling)
d_unpickling = pickle.loads(d_pickling)
print(d_unpickling)


使用pickle.load()方法

with open('pickling.txt', 'rb') as f:d_unpickling = pickle.load(f)print(d_unpickling)

Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。

2.python利用json包的序列化与反序列化

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

JSON类型 Python类型
{} dict
[] list
“string” str
1234.56 int或float
true/false True/False
null None

对于python的内置数据类型的数据,是可以直接序列化为JSON的{},不过,很多时候,我们更喜欢用class表示对象,比如定义Student类,然后序列化,另外对于其他包中的数据类型,比如ndarry等,这些对象是无法直接进行序列化和反序列化的。对于非python内置数据类型的数据,需要我们先将其转化为python内置的数据类型,对于非字典类型的数据,需要转为字典数据,因为只有字典这种键值对数据才可以序列为JSON的对象,同样,在反序列的过程中,再将json对象的相应数据变为其原来的数据类型,同时转为自定义的对象。

2.1 json的序列化与反序列化——python内置的数据类型

Python内置的json模块提供了非常完善的Python对象到JSON格式的转换。

2.1.1 把Python对象变成一个JSON并写入文件

第一种方式 :利用dumps方法
dumps()方法返回一个str,内容就是标准的JSON,然后再将该json写入文件

import jsond = dict(name='Bob', age=20, score=88)
print(d)  # key是单引号
# 将d序列化为json
d_pickling = json.dumps(d)
print(d_pickling)  #  JSON字符串中的key是双引号
print(type(d_pickling))
# 将json写入文件pickling2.json,也可以写入.txt文件等
with open('pickling.json', 'w') as f:f.write(d_pickling)# 从文件中读取json
with open('pickling.json', 'r') as f:d_pickling = f.read()
print(d_pickling)
print(type(d_pickling))


第二种方式:利用dump方法
dump()方法可以直接把JSON写入一个file-like Object

import jsond = dict(name='Bob', age=20, score=88)with open('pickling.json', 'w') as f:json.dump(d, f)with open('pickling.json', 'r') as f:d_pickling = f.read()print(d_pickling)
print(type(d_pickling))

2.1.1 从文件中读取json数据进行反序列化

第一种方式: 利用loads方法
要把JSON反序列化为Python对象,可以用loads(),把JSON的字符串反序列化

import jsond = dict(name='Bob', age=20, score=88)
# 将d序列化为json
d_pickling = json.dumps(d)
# 将json字符串反序列化
d_unpickling = json.loads(d_pickling)
print(d_unpickling)
print(type(d_unpickling))


第二种方式:利用load方法
也可以利用load()方法,从file-like Object中读取字符串并反序列化:

import jsonwith open('pickling.json', 'r') as f:d_unpickling = json.load(f)
print(d_unpickling)
print(type(d_unpickling))

2.2.json的序列化与反序列化——其他的对象

Python的dict对象可以直接序列化为JSON的{},不过,很多时候,我们更喜欢用class表示对象,比如定义Student类,然后序列化,另外对于其他包中的对象,比如ndarry对象等,有时候我们也需要进行序列化与反序列化,这些对象是无法直接进行序列化和反序列化的。

这时,需要我们去定制JSON序列化与反序列化,dumps()方法的参数列表,除了第一个必须的obj参数外,dumps()方法还提供了一大堆的可选参数:这些可选参数就是让我们来定制JSON序列化。关于dumps的官方指南https://docs.python.org/3/library/json.html#json.dumps

其中的可选参数default就是把任意一个对象变成一个可序列为JSON的对象,我们只需要专门写一个转换函数,再把函数传进去即可,就可以将任意对象序列化为json对象。

2.2.1 自定义default转换函数,把其他的对象变成一个JSON并写入文件

第一种方式: 利用dumps方法
例如:

import json
class Student(object):def __init__(self, name, age, score):self.name = nameself.age = ageself.score = scores = Student('Bob', 20, 88)# 定义转换函数,将自定义的对象转换为json对象
def studentdict(std):return {'name': std.name,'age': std.age,'score': std.score}# 将定义的转换函数传入default,然后序列化为json
stu_pickling = json.dumps(s, default=studentdict)
print(stu_pickling)# 将序列化后的json存入文件
with open('pickling.json', 'w') as f:f.write(stu_pickling)# 从文件中读取json
with open('pickling.json', 'r') as f:d_pickling = f.read()


延申:
下次如果遇到一个Teacher类的实例,照样无法序列化为JSON。我们可以偷个懒,把任意class的实例变为dict:

class Student(object):def __init__(self, name, age, score):self.name = nameself.age = ageself.score = scores = Student('Bob', 20, 88)
print(s.__dict__)  # s.__dict__的结果为{'name': 'Bob', 'age': 20, 'score': 88}
# 定义转换函数,将自定义的对象转换为json对象
def studentdict(std):return {'name': std.name,'age': std.age,'score': std.score}# 将定义的转换函数传入default
stu_pickling = json.dumps(s, default=lambda obj: obj.__dict__)
print(stu_pickling)with open('pickling.json', 'w') as f:f.write(stu_pickling)# 从文件中读取json
with open('pickling.json', 'r') as f:d_pickling = f.read()

因为通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。

第二种方式:利用dump方法

import jsonclass Student(object):def __init__(self, name, age, score):self.name = nameself.age = ageself.score = scores = Student('Bob', 20, 88)
# print(s.__dict__)def studentdict(std):return {'name': std.name,'age': std.age,'score': std.score}# 将stu进行序列化,然后存到文件pickling.json
with open('pickling.json', 'w') as f:json.dump(s, f, default=studentdict)# 从文件中读取序列化的json
with open('pickling.json', 'r') as f:stu_pickling = f.read()print(stu_pickling)
print(type(stu_pickling))

2.2.2 自定义object_hook转换函数,从文件中读取json数据进行反序列化为自定义的对象

要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象,然后,我们传入的object_hook函数负责把dict转换为Student实例:
第一种方式: 利用loads方法

import jsonwith open('pickling.json', 'r') as f:stu_pickling = f.read()
print(stu_pickling)
print(type(stu_pickling))def dictstudent(d):return Student(d['name'], d['age'], d['score'])stu_unpickling = json.loads(stu_pickling, object_hook=dictstudent)print(stu_unpickling)


第二种方式: 利用load方法

import jsonwith open('pickling.json', 'r') as f:stu_pickling = f.read()
print(stu_pickling)
print(type(stu_pickling))def dictstudent(d):return Student(d['name'], d['age'], d['score'])with open('pickling.json', 'r') as f:stu_unpickling = json.load(f, object_hook=dictstudent)print(stu_unpickling)

2.2.3 创建一个类,继承json.JSONEncoder,重写default方法进而实现序列化

继承json.JSONEncoder,对其中的default方法进行重写,增加对Student中对象进行序列化的操作。
第一种方式:使用dumps方法

import jsonclass Student(object):def __init__(self, name, age, score):self.name = nameself.age = ageself.score = score# 定义转换函数,将自定义的对象转换为json对象
def studentdict(std):return {'name': std.name,'age': std.age,'score': std.score}s = Student('Bob', 20, 88)class StuEncoder(json.JSONEncoder):def default(self, obj):# 通过判断obj的类型,进行相应的转换,变成可序列化的对象if isinstance(obj, Student):return studentdict(obj)else:return super().default(obj)# 序列化为json
stu_pickling = json.dumps(s, cls=StuEncoder)
with open('pickling.json', 'w') as f:f.write(stu_pickling)print(stu_pickling)
print(type(stu_pickling))

第二种方式:使用dump方法

import json
class Student(object):def __init__(self, name, age, score):self.name = nameself.age = ageself.score = score# 定义转换函数,将自定义的对象转换为json对象
def studentdict(std):return {'name': std.name,'age': std.age,'score': std.score}
s = Student('Bob', 20, 88)class StuEncoder(json.JSONEncoder):def default(self, obj):if isinstance(obj, Student):return studentdict(obj)else:return super(StuEncoder, self).default(obj)# 字典写入文件
with open("pickling.json", 'w') as f:json.dump(s, f, cls=StuEncoder)with open('pickling.json', 'r') as f:stu_pickling = f.read()
print(stu_pickling)
print(type(stu_pickling))

2.2.3 创建一个类,继承json.JSONDecoder,重写decode方法进而实现反序列化

第一种方式:使用loads方法

import jsonclass Student(object):def __init__(self, name, age, score):self.name = nameself.age = ageself.score = score# 定义转换函数
def dictstudent(d):return Student(d['name'], d['age'], d['score'])class StuDecoder(json.JSONDecoder):def decode(self, obj):dic = super().decode(obj)if dic['name'] is not None:return dictstudent(dic)return dic# 从文件pickling.json中读取序列化后的json对象
with open('pickling.json', 'r') as f:stu_pickling = f.read()
print(stu_pickling)
print(type(stu_pickling))stu_unpickling = json.loads(stu_pickling, cls=StuDecoder)print(stu_unpickling)


第二种方式:使用load方法

import json
class Student(object):def __init__(self, name, age, score):self.name = nameself.age = ageself.score = score# 定义转换函数
def dictstudent(d):return Student(d['name'], d['age'], d['score'])class StuDecoder(json.JSONDecoder):def decode(self, obj):dic = super().decode(obj)if dic['name'] is not None:return dictstudent(dic)return dicwith open('pickling.json', 'r') as f:stu_unpickling = json.load(f, cls=StuDecoder)
print(stu_unpickling)

3. 综合的例子

对于这样的一个字典,parameters = {‘w1’: np.arange(10), ‘w2’: np.array([[1, 2, 3], [3, 2, 1]])},将其序列化保存到文件,然后读取文件中的数据,反序列化为原本的数据(数据类型不可改变)。

分析:
首先数据类型是ndarry,非python内置数据类型是无法进行序列化的,所以需要先将其转为python的内置数据类型,由于数据本身就是字典数据了,所以不需要再将其转字典数据了,另外再反序列化时,需要将数据类型在变为Numpy中的对应的数据类型。

import numpy as np
import json
import codecsparameters = {'w1': np.arange(10), 'w2': np.array([[1, 2, 3], [3, 2, 1]])}class NpEncoder(json.JSONEncoder):def default(self, obj):# 通过判断对象类型,来进行特定的序列化操作if isinstance(obj, np.integer):return int(obj)elif isinstance(obj, np.floating):return float(obj)elif isinstance(obj, np.ndarray):return obj.tolist()else:return super().default(obj)class NpDecoder(json.JSONDecoder):def decode(self, obj):dic = super().decode(obj)# 通过判断字典对象中是否有'w1'这个key值,来进行特定的反序列化操作if dic['w1'] is not None:for i in dic.keys():dic[i] = np.array(dic[i])return dicreturn dic# 字典序列化json后保存到文件
with open("para_new.csv", 'w', encoding='utf-8') as f:json.dump(parameters, f, cls=NpEncoder)
# 读取json对象的数据
with open('para_new.csv', 'r', encoding='utf-8') as f:para_pickling = f.read()print(para_pickling)
print(type(para_pickling))# 读取文件中的json,然后反序列化,不对其数据类型进行转化
with open('para_new2.csv', 'r', encoding='utf-8') as f:para_unpickling = json.load(f)print(type(para_unpickling['w1']), type(para_unpickling['w2']))  # 均是list类型 # 读取文件中的json,然后反序列化,设置cls参数,将数据类型变成原来的形式
with open('para_new2.csv', 'r', encoding='utf-8') as f:para_unpickling = json.load(f, cls=NpDecoder)print(type(para_unpickling['w1']), type(para_unpickling['w2']))


关于tolist()方法,可以参考:https://blog.csdn.net/qq_38048756/article/details/107798597

参考:廖雪峰python教程https://www.liaoxuefeng.com/wiki/1016959663602400/1017624706151424

序列化与反序列化——最全教程(含代码示例)相关推荐

  1. linux安装nginx1.21.1全教程(含安装包)

    linux在线安装nginx1.21.1全教程(含安装包) 大家好,我是酷酷的韩金群~ 1.检查是否已安装nginx find -name nginx 如果系统已安装nginx,那么卸载: yum r ...

  2. linux mysql5.7.36 离线安装使用全教程(含安装包)

    linux mysql5.7.36 离线安装使用全教程(含安装包) 大家好,我是酷酷的韩~ 1.前期准备: mysql版本5.7.36 百度网盘下载地址如下: 内含 mysql-5.7.36-linu ...

  3. mybatis-generator生成带中文注释POJO类的超详细教程含代码和图解

    mybatis-generator生成带中文注释POJO类的超详细教程含代码和图解 mybatis-generator自动生成带中文注释POJO类和增删改查,idea和eclipes都可以使用 MyC ...

  4. python pyqt教程_python使用PyQt5的详细教程(代码示例)

    本篇文章给大家带来的内容是关于python使用PyQt5的详细教程(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 一:安装PyQt5pip install pyqt5 二 ...

  5. php json字符串序列化,JSON序列化与反序列化实现方法(附代码)

    这次给大家带来JSON序列化与反序列化实现方法(附代码),JSON序列化与反序列化实现的注意事项有哪些,下面就是实战案例,一起来看一下. 一.JSON简介 JSON(JavaScript Object ...

  6. Java序列化与反序列化最全详解

    什么是序列化和反序列化? 序列化: 序列化就是将 java对象 转化为字节序列的过程. 序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组. 为什么要把Java对象序列化呢?因 ...

  7. 【数据结构与算法】之深入解析“二叉树的序列化与反序列化”的求解思路与算法示例

    一.题目要求 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据. 请设计一个 ...

  8. 快速排序详细图解分析(含代码示例)

    快速排序基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个 ...

  9. OpenCV函数用法详解21~30,含代码示例,可直接运行

    opencv3 文章目录 opencv3 1.图像加权和 2.图像加密与解密 3.数字水印 4.色彩空间类型转换 5.dst = cv2.inRange(src, lowerb, upperb) 6. ...

最新文章

  1. Android 使用git 忽略文件
  2. 基于DQN强化学习训练一个超级玛丽
  3. 《UML面向对象设计基础》—第1章1.2节信息/实现隐藏
  4. 夜间灯光数据dn值_中国区域DMSP/OLS夜间灯光影像的校正
  5. VTK:几何对象之OrientedArrow
  6. 关于void main()的误区
  7. Java黑皮书课后题第6章:**6.26(回文素数)回文素数是指一个数同时为素数和回文数。编程程序,显示前100个回文素数,每行显示10个数,数字中间用一个空格隔开
  8. 使用Volley StringRequest Get的方式进行发票查询操作
  9. CodeForces - 1337D Xenia and Colorful Gems(二分)
  10. 机器学习程序猿在Linux猩球的生存指南
  11. C++中的内联函数和C中的宏定义的区别
  12. 最好的虚拟服务器,最好虚拟主机推荐给大家
  13. 经典游戏扫雷详解--你也可以写出扫雷和玩好扫雷
  14. 14种神笔记方法,只需选择1招,让你的学习和工作效率提高100倍!
  15. git放弃本地修改:
  16. linux build文件,从源代码到可执行文件——编译全过程解析
  17. 西安交通大学护理学计算机考试,西安交通大学护理专业怎么样
  18. 使用计算属性实现购物车功能效果(商品数量增减、单选多选计算金额和总价,)
  19. matlab双纵坐标的绘图命令_MATLAB画双纵坐标
  20. python函数map和split函数

热门文章

  1. PCIe传输速率和可用带宽(吞吐量)计算
  2. 一张图阐述UML时序图(顺序图)的画法【软件工程】
  3. Andriod 开发之微信分享接口
  4. 【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置git环境和项目创建
  5. 我爱Markdown (1)
  6. Selenium 使用教程
  7. 毫秒级的开源投屏软件scrcpy,手机无需安装任何软件
  8. vivo s12和s10的区别
  9. 前端js截取数组的常用方法(记得收藏点赞)
  10. harris位_Harris Corner(Harris角检测)