Python系列教程(三十六):序列化和反序列化

  一、序列化和反序列化  

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)

json数据类型

    ① string: json的字符串是由引号包围起来的任意字符,可以有转义字符

    ② number:正负整数,浮点数

    ③ object:对象,就是Python的字典,格式:{k1:v1,k2:v2}key必须是一个双引号引起的字符串,value可以是任意合法值

object

    ④ array:数组,就是Python的列表,格式:[v1,v2,v3],值之间用‘,’号分割

array

    ⑤ 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/

messagepack

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]

Jimmy's Blog ,版权所有丨如未注明,均为原创丨本网站采用BY-NC-SA协议进行授权,转载请注明转自:https://www.xjimmy.com/python-36-serialization.html

Leave a Comment