Python--序列化和反序列化;Json与MessagePack

为什么要序列化

  • 内存中的字典、列表、集合以及各种对象,如何保存到一个文件中?
  • 如果是自己定义的类的实例,如何保存到一个文件中?
  • 如何从文件中读取数据,并让他们在内存中再次恢复成自己对应的类的实例?
  • 要设一套协议,就按照某种规则,把内存中数据保存到文件中。文件是一个字节序列,所以必须把数据转换成字节序列,输出到文件。这就是序列化。反之,把文件的字节序列恢复到内存并且还是原来的类型,就是反序列化

定义

serialization 序列化

  • 将内存中对象存储下来,把它变成一个个字节 ->二进制

deserialization 反序列化

  • 将文件的一个个字节恢复成内存中对象 -> 二进制

  • 序列化保存到文件就是持久化

  • 可以将数据序列化后持久化,或者网络传输;也可以将文件中或者网络接收到的字节序列反序列化

  • Python提供了pickle库

pickle库

  • Python中的序列化、反序列化模块
    在这里插入图片描述
import pickle

filename = 'o:/ser'

i = 99
c = 'c'
l = list('123')
d = {'a':1, 'b':'abc', 'c':[1,2,3]}

# 序列化
with open(filename, 'wb') as f:
	pickle.dump(i, f)
	pickle.dump(c, f)
	pickle.dump(l, f)
	pickle.dump(d, f)

# 反序列化
with open(filename, 'rb') as f:
	print(f.read(), f.seek(0))
	for i in range(4)
		x =pickle.load(f)
		print(x, type(x))
  • 对象序列化
import pickle

class AAA:
	tttt = 'ABC'
	def show(self):
		print('abc')
	
a1 = AAA() # 创建AAA类的对象

# 序列化
ser = pickle.dumps(a1)
print('ser={}'.format(ser)) # AAA

# 反序列化
a2 = pickle.loads(ser)
print(a2.tttt)
a2.show()
  • 上面的例子中,故意使用了连续的AAA、ABC、abc等字符串,就是为了在二进制文件中能容易的发现它们
  • 上例中,其实就保存了一个类名,因为所有的其他东西都是类定义的东西,是不变的,所以只序列化一个AAA类名。反序列化的时候找到类就可以恢复一个对象
import pickle

# 对象序列化
class AAA:
	def__int__(self):
		self.aaaa = 'abc'

a1 = AAA() # 创建AAA类的对象

# 序列化
ser = pickle.dumps(a1)
print('ser={}.format(ser)) # AAA aaaa abc

# 反序列化
a2 = pickle.loads(ser)
print(a2, type(a2))
print(a2.aaaa)
print(id(a1), id(a2))
  • 可以看出这回除了必须保存的AAA,还序列化了aaaa和abc,因为这是每一个对象自己的属性,每一个对象不一样的,所以这些数据需要序列化

序列化、反序列化实验

  • 定义类AAA,并序列化到文件
import pickle

# 实验
# 对象序列化
class AAA:
	def __init__(self):
		self.aaaa = 'abc'

a1 = AAA() # 创建AAA类的对象

# 序列化
ser = pick.dumps(a1)
print('ser={}'.format(ser)) # AAA aaaa abc
print(len(ser))

filename = 'o:/ser'

with open(filename, 'wb') as f:
	pickle.dump(a1, f)
  • 将产生的序列化文件ser发送到其他节点上
  • 增加一个x.py文件,内容如下。最后执行这个脚本 $ python x.py
import pickle

with open('ser', 'rb') as f:
		a = pickle.load(f) # 异常
  • 会抛出异常**AttributeError: Can’t get attribute ‘AAA’ on <module ‘__main__’ from ‘t.py’>
  • 这个异常实际上是找不到类AAA的定义,增加类定义即可解决
  • 反序列化的时候找到AAA类的定义,才能成功。否则就会抛出异常
  • 可以这样理解:反序列化的时候,类是模子,二进制序列就是铁水
import pickle

class AAA:
	def show(self):
		print('xyz')
	
with open('ser', 'rb') as f:
	a = pickle.load(f)
	print(a)
	a.show()
	print(a.aaaa)
  • 这里定义了类AAA,并且上面的代码也能成功的执行
  • 注意:
    这里的AAA定义和原来完全不同了
    因此,序列化、反序列化必须保证使用同一套类的定义,否则会带来不可预料的结果

序列化应用

一般来说,本地序列化的情况,应用较少。大多数场景都应用在网络传输中。
将数据序列化后通过网络传输到远程节点,远程服务器上的服务将接受到的数据反序列化后,就可以使用了
但是需要注意,远程接受端,反序列化时必须有对应的数据类型,否则就会报错。尤其是自定义类,必须远程得有一致的定义
现在,大多数项目,都不是单机的,也不是单服务的,需要多个程序之间配合。需要通过网络将数据传送到其他节点上去,这就需要大量的序列化、反序列化过程
但是,问题是,Python程序之间还可以都用pickle解决序列化、反序列化,如果是跨平台、跨语言、跨协议。pickle就不太适合,需要公共的协议。例如XML、Json、Protocol Buffer等
不同的协议,效率不同,适用不同的场景,根据不同的情况分析选型

Json

Json(JavaScript Object Notation,JS 对象标记)是一种轻量级的数据交换格式。它基于 ECMAScript(w3c组织制定的JS规范)的一个子集,采用完全独立于变成语言的文本格式来存储和表示数据
Json官网:http://json.org/

Json是数据类型

  • 双引号引起来的字符串,数值,true和false,null,对象,数组。这些都是值
    在这里插入图片描述
  • 字符串:由双引号包围起来的任意字符的组合,可以有转义字符
  • 数值:有正负,有整数、浮点数
  • 对象:无序的键值对的集合
    格式:{key1:value1,…,keyn:valuen}
    key必须是一个字符串,需要双引号包围这个字符串
    value可以是任意合法的值

在这里插入图片描述

  • 数组:有序的值的集合
    格式:[val1,…,valn]
    在这里插入图片描述
  • 实例
{
	"person":[
		{
			"name": "tom",
			"age": 18
		},
		{
			"name": "jerry",
			"age": 16
		}
	],
	"total": 2
}		

Json 模块

Python 与 Json

  • Python支持少量内建数据类型到Json类型的转换

在这里插入图片描述

常用方法

在这里插入图片描述

import json
d = {'name':'Tom', 'age':20, 'interest':('music', 'movie'), 'class':['python']}
j = json.dumps(d)
print(j, type(j)) # 注意引号、括号的变化,注意数据类型的变化

d1 = json.loads(j)
print(d1)
print(id(d), id(d1))

一般json编码的数据很少落地,数据都是通过网络传输。传输的时候,要考虑压缩它
本质上来说它就是个文本,就是个字符串
json很简单,几乎编程语言都支持json,所以应用范围十分广泛

MessagePack

官网:https://msgpack.org/
MessagePack是一个基于二进制高效的对象序列化类库,可用于跨语言通信
它可以像Json那样,在许多语言之间交换结构对象
但是它比Json更快速也更轻巧
支持Python、Ruby、Java、C/C++等众多语言。
兼容json和pickle
在这里插入图片描述

# Json:27 bytes
{"person":[{"name":"tom","age":18},{"name":"jerry",."age":16}],"total":2}

# MessagePack:18 bytes
# 82 a7 63 6f 6d 70 61 63 74 c3 a6 73 63 68 65 6d 61 00

可以看出,大大的节约了空间

安装

$ pip install msgpack

常用方法

  • packb 序列化对象。提供了dumps来兼容pickle和json
  • unpackb 反序列化对象。提供了loads来兼容
  • pack 序列化对象保存到文件对象。提供了dump来兼容
  • unpack 反序列化对象保存到文件对象。提供了load来兼容
import pickle
import msgpack
import json

d = {'person': [{'name': 'tom', 'age': 18}, {'name': 'jerry', 'age': 16}], 'total':2}

# json
data = json.dumps(d)
print(type(data), len(data), data)
print(data.replace(' ', '')
print(len(data.replace(' ', ''))) # 72 bytes 注意这样替换的压缩是不对的

# pickle
data = pickle.dumps(d)
print(type(data), len(data), data) # 101 bytes

# msgpack
data = msgpack.dumps(d)
print(type(data), len(data), data) # 48 bytes

print('-' * 30)

u = msgpack.umpackb(data)
print(typr(u), u)
print(msgpack.loads(data))

u = msgpack.loads(data, encoding='utf-8')
print(type(u), u)
  • MessagePack简单易用,高效压缩,支持语言丰富
  • 所以,用它序列化也是一种很好的选择。Python很多大名鼎鼎的库都是用了msgpack
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值