Python 序列化和反序列化

本文介绍了Python中序列化和反序列化的概念及作用,通过pickle库进行序列化和反序列化试验,指出其在本地和网络传输中的应用场景及局限性。还介绍了Json和MessagePack两种序列化协议,Json是轻量级数据交换格式,应用广泛;MessagePack更高效轻巧,支持多语言。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

序列化和反序列化


为什么要序列化


内存中的字典、列表、集合以及各种对象,如何保存到一个文件中?
如果是自己定义的类的实例,如何保存到一个文件中?
如何从文件中读取数据,并让它们在内存中再次恢复成自己对应的类的实例?

要设计一套 协议,按照某种规则,把内存中数据保存到文件中。文件是一个字节序列,所以必须把数据转换成字节序列,输出到文件。这就是序列化。反之,从文件的字节序列恢复到内存并且还是原来的类型,就是反序列化。

定义


serialization 序列化
将内存中对象储存下来,把它变成一个个字节。 ->二进制

deserialization 反序列化
将文件的一个个字节恢复成内存中对象。 <-二进制

序列化保存到文件就是持久化。
可以将数据序列化后持久化,或者网络传输;也可以将从文件中或者网络接受到的字节序列反序列化。

python 提供了 pickle 库。

pickle 库


Python 中的序列化、反序列化模块

函数说明
dumps对象序列化为 bytes 对象
dump对象序列化到文件对象,就是存入文件
loads从 bytes 对象反序列化
load对象反序列化,从文件读取数据
import pickle
#对象序列化
class AAAA:
    ttt = 'ABC'
    def show(self):
        print('abc')
        
a1 = AAAA() #创建AAAA类的对象
#序列化
ser = pickle.dumps(a1)
print('ser = {}'.format(ser))
#反序列化
a2 = pickle.loads(ser)
print(a2.ttt)
a2.show()

上面的例子中,故意使用了连续的AAAA,ABC,abc 等字符串,就是为了在二进制文件中能容易的发现它们。

上例中,其实就保存了一个类名,因为所有的其他东西都是类定义的东西,是不变的,所以只序列化一个AAAA类名。反序列化的时候找到类就可以恢复一个对象。

import pickle
#对象序列化
class AAA:
    def __init__(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 = pickle.dumps(a1)
print('ser = {}'.format(ser))
print(len(ser))

filename = 'f:/test/tt'
#序列化到文件
with open(filename,'wb') as f:
    pickle.dump(a1,f)

将产生的序列化文件 ser 发送到其他节点上。
增加一个 x.py 文件,内容如下。最后执行这个脚本 $python x.py

import pickle 

with open('tt','rb') as f:
	a = pickle.load(f) #异常

会抛出异常AttributrError: Can't get attribute 'AAA' on <module '__main__' from 't.py'>
这个异常实际上是找不到类 AAA 的定义,增加类定义即可解决。
反序列化的时候要找到 AAA 类的定义,才能成功。否则就会抛出异常。
可以这样理解:反序列化的时候,类是模子,二进制序列就是铁水

import pickle

class AAA:
    def show(self):
        print('xyz')

with open('tt','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 规范)的一个子集,采用完全独立于编程语言的文本格式来储存和表示数据。
http://Json.org/

Json 的数据类型


双引号引起来的字符串,数值,true 和 false, null, 对象, 数组, 这些都是值
在这里插入图片描述字符串
由双引号包围起来的任意字符的组合,可以有转义字符。

数值
有正负、有整数、浮点数


对象
无序的键值对的集合
格式 :{key1:value1,…,keyn:valuen}
key必须是一个字符串,需要双引号包围这个字符串。
value可以是任意合法的值。
在这里插入图片描述


数组
有序的值的集合
格式 :[val1,…,valn]
在这里插入图片描述实例

{
    "person":[
        {
            "name":"tom",
            "age":18
        },
        {
            "name":"jwrry",
            "age":16
        }
    ],
    "total":2
}

json模块


Python 与 json

python 支持少量内建数据类型到 Json 类型的转换。

Python类型Json类型
Truetrue
Falsefalse
Nonenull
strstring
intinteger
floatfloat
listarray
dictobject
常用方法
Python类型Json类型
dumpsjson编码
dumpjson编码并存入文件
loadsjson解码
loadjson解码,从文件读取数据
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


MessagePack 是一个基于二进制高效的对象序列化类库,可用于跨语言通信。
它可以像 JSON 那样,在许多语言之间交换结构对象。
但是它比 JSON 更快速也更轻巧。
支持 Python、Ruby、Java、C/C++ 等众多语言。宣称比 Google Protocol Buffers 还要快4倍。
兼容 Json 和 Pickle。
在这里插入图片描述

#json
# 79 bytes
{"age": 18, "class": ["python"], "interest": ["music", "movie"], "name": "Tom"}

#messagepack
# 51 bytes
#84 a3 61 67 65 12 a5 63 6c 61 73 73 91 a6 70 79 74 68 6f 6e a8 69 6e 74 65 72 65 73 74 92 a5 6d 75 73 69 63 a5 6d 6f 76 69 65 a4 6e 61 6d 65 a3 54 6f 6d

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


常用方法

pcakb 序列化对象。提供了 dumps 来兼容 pickle 和 json。
unpackb 反序列化对象。提供了 loads 来兼容。

pack 序列化对象保存到文件对象。提供了 dump 来兼容。
unpack 反序列化对象-保存到文件对象。提供了 load 来兼容。

import pickle
import json
import msgpack

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

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

#json
data = json.dumps(d)
print(type(data), len(data), data)
print(data.replace(' ', ''))
print(len(data.replace(' ', '')))

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

print('='*30)

u = msgpack.unpackb(data)
print(type(u), u)
print(msgpack.loads(data))


u = msgpack.loads(data, encoding='utf-8')
print(type(u), u)

MessagePack 简单易用,高效压缩,支持语言丰富。
所以,用它序列化也是一种很好的选择。Python 很多大名鼎鼎的库都是用了 msgpack。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值