1 引言

  在日常开发中,所有的对象都是存储在内存当中,尤其是像python这样的坚持一切接对象的高级程序设计语言,一旦关机,在写在内存中的数据都将不复存在。另一方面,存储在内存够中的对象由于编程语言、网络环境等等因素,很难在网络中进行传输交互。由此,就诞生了一种机制,可以实现内存中的对象与方便持久化在磁盘中或在网络中进行交互的数据格式(str、bites)之间的相互转换。这种机制就叫序列化与发序列化:

  序列化:将内存中的不可持久化和传输对象转换为可方便持久化和传输对象的过程。

  反序列化:将可持久化和传输对象转换为不可持久化和传输对象的过程。

  Python中提供pickle和json两个模块来实现序列化与反序列化,pickle模块和json模块dumps()、dump()、loads()、load()这是个函数,其中dumps()、dump()用于实现序列化,loads()、load()用于实现反序列化。下面,我们分别对pickle和json模块进行介绍。

2  pickle模块

  pickle模块的dumps()、dump()、loads()、load()是个函数按功能划分可以分为两组:
  序列化:dumps()、dump()
  反序列化:loads()、load()
  dumps()与dump()的区别是dumps()只是单纯得将对象序列化,而dump()会在序列化之后将结果写入到文件当中;与之对应,loads()与load()区别至于loads()是对dumps的序列化结果进行反序列化,而dump()会从文件中读取内容进行反序列化。

2.1 dumps()与loads()

>>> import pickle
>>> p_dict = {'name':'张三' , 'age':30 , 'isMarried':False} # 定义一个字典
>>> p_str = pickle.dumps(p_dict) # 序列化
>>> type(p_dict)
<class 'dict'>
>>> type(p_str)
<class 'bytes'>
>>> p_str
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x06\x00\x00\x00\xe5\xbc\xa0\xe4\xb8\x89q\x02X\x03\x00\x00\x00ageq\x03K\x1eX\t\x00\x00\x00isMarriedq\x04\x89u.'
>>> p = pickle.loads(p_str)
>>> type(p)
<class 'dict'>
>>> p
{'name': '张三', 'age': 30, 'isMarried': False}

  可以看到,反序列化后得到的p和序列化之前的p_dict内容是一模一样的。不过,p与p_dict已经是两个不同的对象了:

>>> id(p)==id(p_dict)
False

2.2 dump()与load()

  序列化:
>>> import pickle
>>> p_dict = {'name':'张三' , 'age':30 , 'isMarried':False} # 定义一个字典
>>> file = open("my_dump.txt", "wb") # 因为序列化只有的是bites类型,所以必须以wb模式打开
>>> pickle.dump(p_dict, file)
>>> file.close()
  此时,通过上面代码我们已经将p_dict序列化成功,并写入到了一个名为my_dump.txt文件中。你可以找到这个文件,然后将它拷贝到任何电脑上进行反序列化:
>>> file=open("my_dump.txt","rb")
>>> p=pickle.load(file)
>>> file.close()
>>> type(p)
<class 'dict'>
>>> p
{'name': '张三', 'age': 30, 'isMarried': False}
  看,反序列化后得到的内容与序列化之前的内容完全一样。体会到序列化与反序列化的作用了吗?序列化之后的内容可以方便得保存到磁盘中,电脑关机也不怕。

3 json模块

  如果你阅读并理解了上文中关于pickle的部门内容,对于这一部分的json模块内容,你可以不费吹灰之力掌握。上文中说到过,与pickle一样,json模块也提供了dumps()、dump()、loads()、load()则是个函数,且其中区别也与pickle中是个函数的区别是一样的。

3.1 dumps()与loads()

>>> import pickle
>>> p_dict = {'name':'张三' , 'age':30 , 'isMarried':False} # 定义一个字典
>>> import json
>>> p_dict = {'name':'张三' , 'age':30 , 'isMarried':False} # 定义一个字典
>>> p_str = json.dumps(p_dict)
>>> type(p_str)
<class 'str'>
>>> p_str
'{"name": "\\u5f20\\u4e09", "age": 30, "isMarried": false}'
  可以看到,json序列化之后得到的是json格式字符串,但上述json字符串中,中文部分内容显示为了“乱码”。怎么办呢?json的dumps()函数(dump()函数也有)中提供了一个ensure_ascii参数,将该参数的值设置为False,可令序列化后中文依然正常显示。
>>> p_str2 = json.dumps(p_dict, ensure_ascii=False)
>>> p_str2
'{"name": "张三", "age": 30, "isMarried": false}'
  接着上面的内容进行反序列化:
>>> p1 = json.loads(p_str)
>>> p1
{'name': '张三', 'age': 30, 'isMarried': False}
>>> p2 = json.loads(p_str)
>>> p2
{'name': '张三', 'age': 30, 'isMarried': False}

3.2 dump()与load()

>>> import json
>>> p_dict = {'name':'张三' , 'age':30 , 'isMarried':False} # 定义一个字典
>>> file = open('d:/mydump.txt' , 'w')
>>> json.dump(p_dict , file)
>>> file.close()
  当然,你也可以加上ensure_ascii这一参数,并将其值设置为False,这样你打开mydump.txt文件里面的中文就能正常显示。(执行完代码之后,本地会有一个mydump.txt文件,诸位可以验证该内容)
>>> file = open('d:/mydump.txt' , 'w')
>>> json.dump(p_dict , file , ensure_ascii=False)
>>> file.close()
  继续反序列化:
>>> file = open('d:/mydump.txt' , 'r')
>>> p = json.load(file)
>>> file.close()
>>> type(p)
<class 'dict'>
>>> p
{'name': '张三', 'age': 30, 'isMarried': False}
  通过上面内容,pickle和json模块关于序列化与反序列化的操作就介绍完了。我们可以发现,pickle与json两个模块无论是在函数名,还是在功能上,都是机器相似的。既然这样,有了pickle模块,为什么还有json模块的诞生呢?接下来来说说pickle与json模块的区别。

4 pickle模块与json模块的区别

  (1)pickle模块用于Python语言特有的类型和用户自定义类型与Python基本数据类型之间的转换
  json模块用于字符串和python数据类型间进行转换。如下所示,我们自定义一个Person类,分别用pickle和json进行序列化:
>>> class Person:
def __init__(self , name , age , isMarried):
self.name = name
self.age = age
self.isMarried = isMarried
>>> p = Person('张三' , 30 , False)
  使用pickle模块进行序列化与反序列化:
>>> p = Person('张三' , 30 , False)
>>> import pickle
>>> pp = pickle.dumps(p)
>>> type(pp)
<class 'bytes'>
>>> pp
b'\x80\x03c__main__\nPerson\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x06\x00\x00\x00\xe5\xbc\xa0\xe4\xb8\x89q\x04X\x03\x00\x00\x00ageq\x05K\x1eX\t\x00\x00\x00isMarriedq\x06\x89ub.'
>>> p2 = pickle.loads(pp)
>>> type(p2)
<class '__main__.Person'>
>>> p2.name
'张三'
  甚至pickle模块还能够对Peron本身进行序列化:
>>> per = pickle.dumps(Person)
>>> per
b'\x80\x03c__main__\nPerson\nq\x00.'
>>> per2 = pickle.loads(per)
>>> per2
<class '__main__.Person'>
  如果用json对Person实例对象进行序列化,就会报错:
>>> import json
>>> p = Person('张三' , 30 , False)
>>> json.dumps(p)
Traceback (most recent call last):
File "<pyshell#49>", line 1, in <module>
json.dumps(p)
……
TypeError: Object of type 'Person' is not JSON serializable
  如果非要用json对Person对象进行序列化,必须先定义一个将Person对象转化为字典(dict)的方法
>>> def person2dict(per):
return {
'name':per.name ,
'age':per.age ,
'isMarried':per.isMarried
}
>>> p3 = json.dumps(p , default=person2dict)
>>> type(p3)
<class 'str'>
>>> p3
'{"name": "\\u5f20\\u4e09", "age": 30, "isMarried": false}'
>>> p3 = json.dumps(p , default=person2dict , ensure_ascii=False)
>>> type(p3)
<class 'str'>
>>> p3
'{"name": "张三", "age": 30, "isMarried": false}'
  当然,也不能直接进行反序列化,不然也只会得到一个字典:
>>> p4 = json.loads(p3)
>>> type(p4)
<class 'dict'>
>>> p4
{'name': '张三', 'age': 30, 'isMarried': False}
  此时,也要定义一个将字典转换为Person类实例的方法,在进行反序列化:
>>> def dict2person(d):
return Person(d['name'],d['age'],d['isMarried'])
>>> p5 = json.loads(p3 , object_hook=dict2person)
>>> type(p5)
<class '__main__.Person'>
>>> p5.name
'张三'
  (2)pickle序列化结果为bites类型,只适合于Python机器之间的交互。
    json序列化结果为str类型,能够被多种语言识别,可用于与其他程序设计语言交互。
  目前,JSON格式字符串已经成为网络传输中的一种标准格式,所以在web后台开发中通常用json模块来序列化而不是pickle模块。
  JSON和Python内置的数据类型对应如下:
JSON类型
Python类型
{}
dict
[]
list
"string"
'str'或u'unicode'
1234.56
int或float
true/false
True/False
null
None

5 总结

  (1)序列化与反序列化是为了解决内存中对象的持久化与传输问题;
  (2)Python中提供了pickle和json两个模块进行序列化与反序列化;
  (3)dumps()和dump()用于序列化,loads()和load()用于反序列化;
  (4)pickle模块能序列化任何对象,序列化结果为bites类型,只适合于Python机器之间交互;
  json模块只能序列化Python基本类型,序列化结果为json格式字符串,适合不同开发语言之间交互。

Python开发之序列化与反序列化:pickle、json模块使用详解的更多相关文章

  1. python json模块 超级详解

    JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式.JSON的数据格式其实就是python里面的字典格式,里面可以包含方括号括起来的数组,也 ...

  2. Python 双向队列Deque、单向队列Queue 模块使用详解

    Python 双向队列Deque 模块使用详解 创建双向队列Deque序列 双向队列Deque提供了类似list的操作方法: #!/usr/bin/python3 import collections ...

  3. Python: json模块实例详解

    ref:https://www.jianshu.com/p/e29611244810 https://www.cnblogs.com/qq78292959/p/3467937.html https:/ ...

  4. python day7: time,datetime,sys,pickle,json模块

    目录 python day 7 1. time模块 2. datetime模块 2.1 date类 2.2 time类 2.3 datetime类 2.4 timedelta类 2.5 tzinfo时 ...

  5. Python开发环境Wing IDE之Search in Files工具详解

    Search in Files工具是Wing IDE中最强大的搜索选项.它支持磁盘.项目,打开编辑器,或其它文件集的多文件批量搜索.它还可以使用通配符搜索,并可以做基于正则表达式的搜索/替换. 建议用 ...

  6. 模块讲解----pickle模块(只在python用的序列化与反序列化)

    特点 1.只能在python中使用,只支持python的基本数据类型. 2.可以处理复杂的序列化语法.(例如自定义的类的方法,游戏的存档等) 3.序列化的时候,只是序列化了整个序列对象,而不是内存地址 ...

  7. python类库32[序列化和反序列化之pickle]

      一 pickle pickle模块用来实现python对象的序列化和反序列化.通常地pickle将python对象序列化为二进制流或文件.   python对象与文件之间的序列化和反序列化: pi ...

  8. 序列化与反序列化之JSON

    在不同编程语言之间传递对象,须把对象序列化为标准格式,比如XML 但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可被所有语言读取,也可方便地存储到磁盘或者通过网络传输 JSON不 ...

  9. Java对象序列化与反序列化一 JSON

    Java对象序列化与反序列化一 JSON 1. 依赖库 jackson-all-1.6.1.jar 2. 代码 public class Student {    private String nam ...

随机推荐

  1. saltstack系列~第四篇

    简介 针对mysql的sls编写0 软件包推送部分  tool_rsync:     file.recurse:        - source: salt://files/mysql        ...

  2. python用win32pdh模块查看进程信息

    import win32pdh def get_processes(): win32pdh.EnumObjects(None, None, win32pdh.PERF_DETAIL_WIZARD) # ...

  3. C/C++杂记:深入虚表结构

    1. 虚表与“虚函数表” 在“C/C++杂记:虚函数的实现的基本原理”一文中曾提到“虚函数表”的概念,只是为了便于理解,事实是:虚函数表并不真的独立存在,它只是虚表(virtual table)中的一 ...

  4. linux 内核是什么?

    一:linux系统如何构成的?User space:User Applications and GNU C library (glibc)kernel space:System Call interf ...

  5. 今天刚用asp.net做的导出Eecel

    protected void daochu_Click(object sender, EventArgs e)        {                string hql = "s ...

  6. java.lang.Math

    四舍五人 System.out.println(Math.round(1.8f));//输出位2 static(静态)方法random() //: object/Shifting.java packa ...

  7. 树链剖分边权模板spoj375

    树链剖分是树分解成多条链来解决树上两点之间的路径上的问题 如何求出树链:第一次dfs求出树上每个结点的大小和深度和最大的儿子,第二次dfs就能将最大的儿子串起来并hash(映射)到线段树上(或者其他数 ...

  8. Python 3 官方文档学习(1)

    本文系官方文档翻译之作,不当之处,敬请原谅! range()函数 如果需要遍历一个数字序列,可以使用内置的range函数.该函数会生成等差序列. 1 2 3 range(5)# 范围[0, 5) ra ...

  9. Android SDK安装及配置模拟器

    环境搭建 1.安装JDK 2.下载Android sdk exe格式和zip格式都可以 3.安装installer_r24.4.1-windows.exe文件,里面有两个应用程序: "SDK ...

  10. 文件中用WriteLine追加内容的两种方法

    if (!Directory.Exists("C:\\testll")) { Directory.CreateDirectory("C:\\testll"); ...