Python序列化和反序列化 - vip共享吧
  • 网站首页
  • IT技术笔记
    • Java教程
    • MySql数据库
    • PHP开发
    • Python教程
    • JavaScript
    • SEO优化
    • 常用工具
  • 好资源福利
    • 会员账号共享
  • 网站模板源码
    • 小程序源码
    • 网站源码
  • 共享网络资源
  • 更多功能
    • 留言吐槽
    • 文章归档
    • 我的邻居
    • 史上今日
    • 视频解析
    • 高清壁纸
    • 公告动态
    • 广告合作
    • 关于我们


导航菜单
  • 网站首页
  • IT技术笔记
    • Java教程
    • MySql数据库
    • PHP开发
    • Python教程
    • JavaScript
    • SEO优化
    • 常用工具
  • 好资源福利
    • 会员账号共享
  • 网站模板源码
    • 小程序源码
    • 网站源码
  • 共享网络资源
  • 更多功能
    • 留言吐槽
    • 文章归档
    • 我的邻居
    • 史上今日
    • 视频解析
    • 高清壁纸
    • 公告动态
    • 广告合作
    • 关于我们
Python

Python序列化和反序列化

2024/9/6 韩俊  Python教程 518 0

当程序运行起来时(也就是进程),所有的变量都保存在内存中, 当进程结束后,该进程申请的内存都要被操作系统回收,我们在内存中的数据就会丢失, 如果想使数据持久化,我们可以把数据存储在磁盘上。但是文件对象只能处理字符流或字节流,如果我们要存储的数据类型为其它类型(int,float,bool,list,tuple,dict等等)应该怎么办呢?

不但读写磁盘需要通过文件对象,网络传输数据也需要通过文件对象,因为网络 IO 是指通过文件对象读写网卡而已,磁盘 IO 是指通过文件对象读写磁盘而已。我们知道文件对象只能处理字符流或字节流,如果我们想把非字符或字节类型(int,float,bool,list,tuple,dict等等)的数据通过网络发送到其它机器上应该怎么办呢?

根据以上两个问题,我们本节课就来学习一下序列化:我们把变量从内存中变成可存储或传输的过程(也就是变成字符流或字节流的过程),称之为序列化,序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反之,能把序列化后的字符流或字节流还原成序列化之前的类型数据的过程叫反序列化。

pickle 模块

在 Python 中有两个模块可以对数据进行序列化和反序列化:cPickle 和 pickle。这两个模块功能是一样的,区别在于 cPickle 是 C 语言写的,速度快;pickle 是纯 Python 写的,速度慢。我们用的时候可以先尝试导入 cPickle,如果失败,再导入 pickle。注意:在 Python 3 中,pickle 序列化的结果是字节流。

try:
    import cPickle as pickle
except ImportError:
    import pickle

mylist = [1, True, "hello"]
seqdata = pickle.dumps(mylist)   # 序列化成字节流
print(type(seqdata))             # list 类型数据序列化成 Bytes 类型
print(seqdata)                   # 序列化后的字节流

mylistreseq = pickle.loads(seqdata)  # 把被序列化的字节流反序列化成 list
print(type(mylistreseq))             # list 类型
print(mylistreseq)                   # 反序列化后的 list

我们可以把 Python 内置的各种类型的数据序列化成字符流或字节流数据,然后用文件对象存储到磁盘上。 同样,我们也可以用文件对象读出这些序列化后的字符流或字节流,然后反序列化成它原来的类型数据到内存中。

try:
    import cPickle as pickle
except ImportError:
    import pickle

mylist = [1, True, ("hello", None)]
f = open("d:/test.txt", "wb")        # 用 wb 写入的是字节流
seqdata = pickle.dumps(mylist)       # 序列化成字节流
f.write(seqdata)
f.close()

f = open("d:/test.txt", "rb")        # 用 rb 读取的是字节流
seqdata = f.read()
f.close()
mylistreseq = pickle.loads(seqdata)  # 反序列化后的 list
print(mylistreseq)

对于我们自定义类型,同样可以使用 pickle 进行序列化。

try:
    import cPickle as pickle
except ImportError:
    import pickle

class myclass(object):
    def __init__(self):
        self.data = 250

    def func(self):
        print("ok")

myobject = myclass()
xx = pickle.dumps(myobject)

yy = pickle.loads(xx)
print(yy.data)
yy.func()

虽然我们可以使用 pickle 序列化自定义对象,但是只有序列化这个对象的程序本身认识该对象,如果我们把序列化后的字符串存到磁盘上,用另一个程序进行反序列化;或者通过网络发送给其它程序进行反序列化。我们都需要在反序列化的程序中定义该类,否则程序不知道这个类型是什么,就会报错。

try:
    import cPickle as pickle
except ImportError:
    import pickle

class myclass(object):
    def __init__(self):
        self.data = 250

    def func(self):
        print("ok")

myobject = myclass()
xx = pickle.dumps(myobject)
f = open("d:/tt.txt", "wb")
f.write(xx)
f.close()
'''
这是另一个程序
'''
import pickle

try:
    import cPickle as pickle
except ImportError:
    import pickle

# 一定要定义一个和序列化程序中的那个类一样的类,否则会报错
class myclass(object):
    def __init__(self):
        self.data = 250

    def func(self):
        print("ok")

f = open("d:/tt.txt", "rb")
xx = f.read()
myobject = pickle.loads(xx)
print(myobject)
print(myobject.data)
myobject.func()

序列化就像中介一样,它把我们内存中的某个类型的数据根据一定的算法转换成字符流或字节流。同样,反序列化就是把序列化后的字符流或字节流按一定的算法再还原成它原来的样子。注意 pickle 只支持序列化和反序列化 Python 中的各种类型的数据。我们考虑以下几种场景:1:如果我们文件内的数据是其它语言序列化后的,我们就没有办法用 pickle 模块进行反序列化。 2:更常见的需求是我们在做网络通信的程序,比如 C/S 模式的即时通讯程序,我们需要在客户端和服务器之间我们要做数据通信, 客户端和服务器采用的语言不可能是同一种,比如我们客户端用 Python 语言,服务器用 C++ 语言等。 3:还有现在的 B/S 模式的网站程序,前端用 js 语言,后端用 java,php,python等等。 这时候我们就需要一种各种主流语言都支持的模块,这个模块可以把不同语言的数据类型序列化成统一的数据类型,然后反序列成相应语言的数据类型, 这个模块就是 json 模块,json 就如英文一样,如果中文和日文需要交流,可以先翻译成英文,然后在翻译成自己的语言。

json 模块

Python 内置了json 模块,可以实现序列化和反序列化,几乎所有的语言都支持 json,比如 C,C++,C#,Java,PHP,Python,Js等等,json 的使用方法和 pickle 类似。注意:json 序列化的结果是字符流。

import json

mylist = [1, True, ("hello", None)]
f = open("d:/test.txt", "w")
seqdata = json.dumps(mylist)       # 序列化成字符流
f.write(seqdata)
f.close()

f = open("d:/test.txt", "r")
seqdata = f.read()
f.close()
mylistreseq = json.loads(seqdata)  #  反序列化后的 list
print(mylistreseq)

json 肯定只能支持所有语言都共有的数据类型,比如 int,float,bool 等这些类型,但是并不是所有语言的类型都是一样的,比如 Python 的 set 类型在其它语言中就没有,json 就不会支持对这种类型数据的序列化和反序列化。

import json

myset = set([3, 4, 5])
data = json.dumps(myset)    # 错误

Python 中的 tuple 类型在其它语言中也没有,但是 tuple 类型和 list 类型很相似,所以 json 会把 tuple 类型数据序列化和反序列化成 Python 的 list 类型数据。 如果是用其它语言进行反序列化我们序列化好的 Python 中的 tuple 类型数据,则会反序列化成其它语言对应的数组类型。

import json

mytuple = (1, 2, 4)
data = json.dumps(mytuple)
dd = json.loads(data)
print(type(dd))  # 
print(dd)        # [1, 2, 4]

Python 中的 dict 类型在其它语言中有类似的类型,比如 C++ 中的 map,Js 中的 object 等等,但是他们的格式有些不同,比如 C++ 中的 map 的键只允许字符串类型等等。我们用 json 序列化和反序列化 Python 的 dict 类型数据,就会只支持键为字符串的 dict,如果键是其它基本数据类型 json 模块会把他转为相应的字符串,如果是 tuple 类型则会报错。

import json

seqdata = json.dumps({1: 1, 1.1: 2, "a": 3, None: 4, True: 5})  # 序列化成字符流,并且对不是字符串类型的键做强制转换
dd = json.loads(seqdata)
print(dd)  # {u'a': 3, u'1': 5, u'null': 4, u'1.1': 2}

seqdata = json.dumps({(1,2): 1})  # 虽然字典本身没问题,但是使用 json 序列化会报错

我们可以把 json 表示的数据类型看成中介数据类型,任何语言的数据类型都对应着同样的 json 数据类型。 假如我们客户端用 Python 语言编写,服务器端用 C++ 语言编写,客户端需要发送数据给服务器端,就如我们把 Python 的数据类型看成日文,json 的数据类型看成英文,C++ 的数据类型看成中文, 先把日文翻译成英文,然后再翻译成中文,这样 C++ 就看的明白 Python 的数据类型了。 下面我们看下 Python 的数据类型对应的 json 数据类型的关系图,当然其它语言的数据类型也对应这同样的 json 数据类型。

python 类型 json 类型 说明
dict {} 序列化时:dict 的键只能为字符串,否则会做相应转换或报异常
list 或 tuple [] 序列化时:tuple 会被序列化成 list 形式的字符流
str 或 unicode unicode 序列化和反序列化时:默认会把字符串序列化和反序列化成 unicode 编码格式
int int 无差别
float float 无差别
bool bool 序列化时:会把 True 会变成 "true" 字符流,False 变成 "false" 字符流;反序列化时:会把 "true" 字符流变成 True,"false" 字符流变成 False
None null 序列化时:会把 None 会变成 "null" 字符流;反序列化时:会把 "null" 字符流变成 None
set 错误 json 不支持对 set 类型进行序列化

我们研究一下 json 序列化是怎么做的,我们发现 json 序列化后的字符流可读性很好,虽然是字符串,但看上去保留着原来的形式。

import json

a = 1
b = 1.1
c = True
d = None
e = "hello"
f = [1, 2]
g = (1, 2)
h = {"a":1, "b": 2}

print(json.dumps(a))  # '1'
print(json.dumps(b))  # '1.1'
print(json.dumps(c))  # 'true'
print(json.dumps(d))  # 'null'
print(json.dumps(e))  # '"hello"'
print(json.dumps(f))  # '[1, 2]'
print(json.dumps(g))  # '[1, 2]'
print(json.dumps(h))  # '{"a":1, "b": 2}'

我们知道 Python 自有的数据类型有哪些可以使用 json 进行序列化,但是我们自定义的类对象是否可以用 json 序列化呢,比如我们定义一个 Human 类,然后对 Human 类的对象进行序列化。

import json

class Human(object):
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

oneman = Human('如花', 18, "女")
seqdata = json.dumps(oneman)  # 抛出异常,...is not JSON serializable

上面的代码之所以无法把 Human 类对象序列化为 json,是因为默认情况下,json 模块中的 dumps 函数不知道如何将 Human 对象变为一个 json 对象。 dumps 函数的可选参数 default 就是把任意一个对象变成一个可序列为 json 的对象,我们只需要为 Human 类专门写一个转换函数,再把函数传进去即可。

import json

class Human(object):
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

def human2dict(oneman):
    return {
    'name': oneman.name,
    'age': oneman.age,
    'sex': oneman.sex
    }

oneman = Human('如花', 18, "女")
print(json.dumps(oneman, default=human2dict))

因为通常类的对象都有一个 __dict__ 属性,它就是一个 dict,用来存储实例变量。也有少数例外,比如定义了 __slots__ 的 类。同样的道理,如果我们要把 json 反序列化为一个 human 类的对象,json 模块的 loads 函数首先转换出一个 dict 对象,然后,我们传入的 object_hook 函数负责把 dict 转换为 human 类的对象。

import json

class Human(object):
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

def human2dict(oneman):
    return {
    'name': oneman.name,
    'age': oneman.age,
    'sex': oneman.sex
    }

def dict2human(d):
    return Human(d['name'], d['age'], d['sex'])

oneman = Human('如花', 18, "女")
json_str = json.dumps(oneman, default=human2dict)  # 序列化 oneman 对象
print(json_str)  # '{"name": "如花", "age": 18, "sex": "女"}'

recoveroneman = json.loads(json_str, object_hook=dict2human)  # 反序列成 Human 对象
print(recoveroneman)

我们仔细思考一下,自定义对象的属性是什么,其实自定义对象的属性最终还是由 Python 内置的数据类型表示的。我们对自定义对象进行序列化,本质是就是对对象的所有属性进行序列化,这些属性最终是由 Python 内置的数据类型表示的,我们只需要序列化这些数据就可以了,无论我们是把这些序列化后的数据存储在磁盘上还是通过网络发送给其它机器,只需要存储或发送对象的所有属性即可。

import json

class Human(object):
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

oneman = Human('如花', 18, "女")
onemandata = {"name": oneman.name, "age": oneman.age, "sex": oneman.sex}

seqdata = json.dumps(onemandata)  # 序列化对象含有的属性
print(seqdata)

reseqonemandata = json.loads(seqdata)  # 反序列化
print(reseqonemandata)

有些脑筋转不过圈的同学可能会想,那序列化的对象如果有函数怎么办? 你只需要在反序列方定义一个和序列化程序中的那个类一样的类,成员函数你当然也写出来了,自然可以调用。

'''
序列化方代码
'''
import json

class Human(object):
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def myfunc(self):
        print(self.name)

def dict2human(d):
    return Human(d['name'], d['age'], d['sex'])

oneman = Human('如花', 18, "女")
onemandata = {"name": oneman.name, "age": oneman.age, "sex": oneman.sex}

seqdata = json.dumps(onemandata)  # 序列化对象含有的属性
print(seqdata)


'''
反序列化方代码
'''
class Human(object):
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def myfunc(self):
        print(self.name)

reseqonemandata = json.loads(seqdata, object_hook=dict2human)  # 反序列化成 Human 类的对象
reseqonemandata.myfunc()  # 完全没问题

本节重要知识点

熟练使用 pickle 模块

熟练使用 json 模块。

知道 pickle 和 json 的区别

点赞:0 分享

上一篇
Python异常处理
下一篇
Python内存操作的文件对象 StringIo 和 BytesIO
作者头像 作者名称 作者性别
韩俊

热门推荐

1 《Python编程从入门到精通》由浅入深地讲解Python语言开发
2 Python中hashlib模块详解
3 python搜索模块的路径
4 Python3的构造函数和访问控制
5 python文件和目录操作
6 Python自定义模块

评论列表

取消回复

    •  
      Login

      韩俊

      趁你现在还有时间,尽你自己最大的努力,努力做成你最想做的那件事,成为你最想成为的那种人,过着你最想过的那种生活。这个世界永远比你想的要更精彩,不要败给生活。

      退出登陆
      • 10076文章
      • 455评论
      • 80微语
  • 广告赞助

  • 二零二五年07月
    一二三四五六日
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
  • 分类

    • 网站模板源码
    • IT技术笔记
    • 好资源分享
    • 共享网络资源
  • 最新文章

      • 经典的黄句子
        • 迷雾通:免费使用的VPN软件
          • 宝塔如何配置SSH密钥,并使用WinSCP工具远程连接服务器
            • 京东外卖商户入驻指南及详细入驻攻略
              • git教程及git常用命令指南
                • 幼儿端午祝福语简短句
                  • 端午简短祝福语送家人
                    • 端午文案祝福语简短励志
  • 热门文章

    • 酷狗音乐VIP账号 酷狗音乐会员账号共享2017.01.29更新
    • 芒果tv vip会员账号 芒果tv会员账号共享2017.01.29更新
    • 爱奇艺vip账号 爱奇艺/PPS会员账号共享2016.12.12更新
    • 优酷/土豆vip会员账号 优酷会员账号共享2017.01.29更新
    • 活动:免费获得爱奇艺VIP/PPS会员账号50天以上的使用权!
    • 酷我音乐VIP账号 酷我音乐会员账号共享2016.12.31更新
    • 暴风影音会员账号 暴风影音会员账号共享2016.12.31更新
    • m1905会员账号 m1905会员账号共享2016.10.21更新
  • 最新评论

    • https://www.vipshare8.com/content/templates/meta/Static/images/tx/10.jpg

      你丫的 文章写得太好了 支持下!![F3...

    • https://www.vipshare8.com/content/templates/meta/Static/images/avatar.jpg

      很棒!刚在某网站看到这个,很欣赏,可惜下...

    • https://www.vipshare8.com/content/templates/meta/Api/qqtx.php/?qq=3861064027

      呃呃呃 oooo

    • https://www.vipshare8.com/content/uploadfile/202103/thum-490d1614564497.png

      回复了111:根据激活的时间有一年的有效期!

    • https://www.vipshare8.com/content/templates/meta/Api/qqtx.php/?qq=792480561

      到2025就到期了吗?

    • https://www.vipshare8.com/content/uploadfile/202103/thum-490d1614564497.png

      [blockquote]打卡时间:16:...

    • https://www.vipshare8.com/content/templates/meta/Static/images/tx/7.jpg

      俊哥,想借用迅雷一用!但需要手机验证!看...

    • https://www.vipshare8.com/content/templates/meta/Api/qqtx.php/?qq=3293901900

      感谢大大的分享

    • https://www.vipshare8.com/content/uploadfile/202103/thum-490d1614564497.png

      回复了好奥v:如果没有解析成功,可以切换接口...

    • https://www.vipshare8.com/content/templates/meta/Api/qqtx.php/?qq=131241242441

      现在视频解析网站怎么用不了啦?

  • 网站统计 I 当前在线:655人

    • 本站管理:1位
    • 用户总数:591位
    • 置顶文章:2篇
    • 日志总数:10076篇
    • 微语总数:80条
    • 评论总数:455条
    • 标签总数:83条
    • 页面总数:8页
    • 分类总数:14个
    • 链接总数:16条
    • 运行天数:3715天
    • 最后更新:6月28日
    • 登录
    • 注册
    • 找回
    Copyright © 2025vip共享吧网站地图 网站备案豫ICP备19004194号-1

    免责声明:本站资源仅供用于学习和交流,本站部分素材内容来源于网络,如有侵权/投稿等,请及时联系站长.

    • 首页
    • 秒懂百科 秒懂百科
    • 搜索
    • 史上今日

    大家都在搜

    • nginx
    • 2345网址导航
    • 华数tv会员账号分享
    • 网易云音乐会员
    • 网盘赚钱
    • 土豆vip账号
    • chatGPT
    • 芒果tv会员
    • 搜狐视频vip账号
    • 爱奇艺vip账号
    • qq音乐vip账号共享
    • swoole
    • VIP电影
    • 网赚
    • 迅雷VIP账号共享
    • 起点vip账号共享
    • 
    • 