一、序列化和反序列化
1、什么是序列化和反序列化
在前面的讲解中,我们知道,数据要在网络中传输或者持久化到磁盘文件中,一定要先转换成字节流(二进制流),比如一个str字符串类型数据,我们可以通过encode编码成字节码,但是如果是一个其他的数据对象呢,比如一个list,一个dict呢,如何将它们保存到文件当中,这就需要用到序列化。
所谓序列化,就是把一个在内存当中的python对象通过某种协议或者标准,转换成二进制类型的数据。
既然有序列化,就有反序列化,是一个完全相反的过程,从磁盘文件或者网络中读取到二进制数据,将它们转换成内存中可操作的对象,这就是反序列化。
2、有哪些序列化方案
就像编码有多种编码格式一样,序列化也有多种序列化方案,不同的序列化方案,转换成的二进数数据也不一样,他们之间是有性能和特性差别的,但是只要保证序列化和反序列化是同一种方案既可。
常用的序列化方案有:pickle,xml,json,messagepack
3、序列化和反序列化方法
在python中,虽然有多种序列化方案,但是统一了调用方法名称,便于我们记忆。
序列化:使用dumps或者dump方法
dumps:将 内存对象 序列化为 字节对象
dump:将 内存对象 序列化到 文件对象(就是存入文件)
反序列化:使用loads和load方法
loads:将 字节对象 反序列化为 内存对象
load:从 文件对象 反序列化 内存对象
dumps和loads是一对,它们的数据是不落地的,也就是在内存当中,dump和load是一对,它们的数据是要落地到磁盘文件当中的。
4、序列化的应用场景
一般来说,本地序列化应用的比较少,大多数场景还是应用在网络传输中,因为网络传输也必须首先是二进制数据,所以先在本地将需要传输的数据进行序列化后,然后通过网络传输给远程节点,远程节点拿到序列化数据后,就进行反序列化成自己的数据对象。
二、pickle模块
1、pickle介绍
pickle是python提供的一种序列化方案,它能跨平台,但是不能跨语言,也就是说,用python的pickle序列化的数据,只有python能认识和反序列化。
2、pickle序列化实验
① 使用dumps和loads序列化常用的数据结构
pickle.dumps(obj) -> 字节数据
pickle.loads(字节数据) -> obj
>>> import pickle >>> d = {'a':1,'b':'我爱你','c':[1,2]} >>> l = [1,2,['a','b']] >>> t = ('let','///') #序列化一个字典 >>> dp = pickle.dumps(d) >>> dp "(dp0\nS'a'\np1\nI1\nsS'c'\np2\n(lp3\nI1\naI2\nasS'b'\np4\nS'\\xe6\\x88\\x91\\xe7\\x88\\xb1\\xe4\\xbd\\xa0'\np5\ns." #序列化一个列表 >>> lp = pickle.dumps(l) >>> lp "(lp0\nI1\naI2\na(lp1\nS'a'\np2\naS'b'\np3\naa." #序列化一个元组 >>> tp = pickle.dumps(t) >>> tp "(S'let'\np0\nS'///'\np1\ntp2\n." #反序列化为一个字典 #这是在python 2.7中实验的,无法编码中文,在python 3中是没有问题的 >>> pickle.loads(dp) {'a': 1, 'b': '\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0', 'c': [1, 2]} #反序列化为一个列表 >>> pickle.loads(lp) [1, 2, ['a', 'b']] #反序列化为一个元组 >>> pickle.loads(tp) ('let', '///')
② 使用dump和load序列化常用的数据结构,将序列化数据落地到磁盘
pickle.dump(obj,file_obj) -> 字节数据
pickle.load(file_obj) -> obj
说明:在使用dump和load进行序列化和反序列化时,指定的那个文件对象需要以‘b’模式打开。
#将d这个字典对象,通过pickle序列化,然后将序列化后的数据落地到磁盘文件中 >>> with open('dump.file','wb') as f: >>> pickle.dump(d,f) #从磁盘文件中中读取二进制数据,通过pickle进行反序列化成字典对象 >>> with open('dump.file','rb') as f: >>> a = pickle.load(f) >>> print(a) {'a': 1, 'c': [1, 2], 'b': '\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0'}
3、序列化的本质
我们通过一组实验来分析序列化的本质到底是什么?
我们知道,在python中,一切皆对象,那就是说一切皆可序列化咯?前面我们是序列化了内置的数据结构,我们现在来试一下序列化自定义类的对象看看结果又是如何。
关于类这里没有讲过,但是只是一个简单的定义和实例化,不影响阅读。
① 序列化一个自定义类对象,这个对象没有自己的属性
>>> import pickle #简单定义一个Test类,它有两个属性‘name’和‘show’。 >>> class Test: >>> name = 'jimmy' >>> def show(name): >>> print(name) #实例化一个对象‘t’ >>> t = Test() #查看对象‘t’的属性为空,说明对象‘t’没有自己的属性 >>> t.__dict__ {} #可以看到,序列化一个自定义对象,只是保存了类名 >>> pickle.dumps(t) '(i__main__\nTest\np0\n(dp1\nb.'
② 序列化一个自定义类对象,这个对象拥有自己的属性
#定义一个简单类, >>> class Test2: >>> def __init__(self): >>> self.name = 'jimmy' >>> t2 = Test2() #查看对象‘t2’的属性 >>> t2.__dict__ {'name': 'jimmy'} >>> pickle.dumps(t2) "(i__main__\nTest2\np0\n(dp1\nS'name'\np2\nS'jimmy'\np3\nsb."
分析和总结:
通过实验① 和实验②的对比,应该能看出些端倪了,一个对象序列化是序列化了哪些东西,其实就是实例化对象的类名,还有属于对象的属性,而反序列化,其实就是拿到这个类名,实例化一个对象,然后给这个对象添加属于它的属性。
如果是这样的话,那么一个对象序列化之后,通过网络传给远程节点,远程节点要反序列化的时候,是需要拿这个类进行实例化的,如果远程节点没有这个类定义,那就会报错,而且就算远程节点定义了这个类,但是类定义的不同,序列化后的结果也会不同。所以需要保证序列化和反序列化是同一个类定义。
三、json
1、什么是json
json:JavaScript object notation,JS对象标记,它是一种非常通用的、轻量级的数据序列化标准格式,它不仅可以跨平台,还可以跨语言,比如python序列化的json格式的数据传给java,java拿到进行反序列化照样可用,是完全独立于编程语言的的文本格式,可以被所有语言读取,也可以非常方便的存储磁盘或者通过网络传输。
json本质上也是一个文本,一个字符串。
2、json的数据类型
json和python一样,有多种数据类型和两种数据结构,而且它们也很相似,可以类比理解。
常用的数据类型:字符串(string)、数值(number)、true、false、 null
两种数据结构:对象(object)或者数组(array)
① string: json的字符串是由双引号包围起来的任意字符,可以有转义字符
② number:正负整数,浮点数
③ object:对象,就是Python的字典,格式:{k1:v1,k2:v2},key必须是一个双引号引起的字符串,value可以是任意合法值
④ array:数组,就是Python的列表,格式:[v1,v2,v3],值之间用‘,’号分割
⑤ true,flase:就是Python的True,False
⑥ null:就是Python的None
3、常用的json数据格式
① 对象:{"name":"Michael","age":24}
② 数组:[{"name":"Michael","age":24},{"name":"Tom","age":25}]
③ 值:{"name":"Michael", "birthday":{"month":8,"day":26}}
json的数据结构可以互相嵌套,所以格式可以多种多样。
4、json模块
json模块同样提供了dumps,loads,dump,load方法,作用都是一样的,就是序列化和反序列化
json.dumps(obj) -> json格式数据
json.loads(json格式数据) -> obj
json.dump(obj,file_obj) ->序列化成json数据,并写入文件
json.load(file_obj) ->从文件读取json数据,并反序列化为对象
>>> import json >>> json_data = [{"name":"Michael","age":24},{'name':"Tom","age":25},(123,23),None,True] #将Python的数据对象转换成json格式 >>> a = json.dumps(json_data) #注意类型的转换 '[{"age": 24, "name": "Michael"}, {"age": 25, "name": "Tom"}, [123, 23], null, true]' #将json格式的数据转换成Python的数据对象 >>> json.loads(a) [{'name': 'Michael', 'age': 24}, {'name': 'Tom', 'age': 25}, [123, 23], None, True]
四、messagepack
1、什么是messagepack
messagepack是另外一种序列化方案,它类似json,但是要比json更轻量化和高效,也可以跨语言进行数据的交换,支持多种语言,兼容pickle和json.
官方网站:https://msgpack.org/
2、messagepack使用
① 安装:pip install msgpack
② 使用方法还是一样,那4个方法:dumps,loads,dump,load
>>> import msgpack >>> data = [{"name":"Michael","age":24},{'name':"Tom","age":25},(123,23),None,True] >>> b = msgpack.dumps(data) >>> b b'\x95\x82\xa4name\xa7Michael\xa3age\x18\x82\xa4name\xa3Tom\xa3age\x19\x92{\x17\xc0\xc3' >>> print(msgpack.loads(b)) [{b'name': b'Michael', b'age': 24}, {b'name': b'Tom', b'age': 25}, [123, 23], None, True]