序列化模块
将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化。
导引
比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给? 现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来。 但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中。 你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢? 没错序列化的过程就是从dic 变成str(dic)的过程。现在你可以通过str(dic),将一个名为dic的字典转换成一个字符串, 但是你要怎么把一个字符串转换成字典呢? 聪明的你肯定想到了eval(),如果我们将一个字符串类型的字典str_dic传给eval,就会得到一个返回的字典类型了。 eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。 BUT!强大的函数有代价。安全性是其最大的缺点。 想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。 而使用eval就要担这个风险。 所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)
序列化:转向一个字符串数据类型的过程,所以所说的序列就是字符串;
序列化的原因:
序列化的根本原因是:数据的传输和存储
1、网络上数据的传输都是bytes类型,这时候就需要将字典等数据类型转换成字符串,然后再转换成bytes类型;——数据传输
2、在向文件里面写内容的时候就需要将字典等数据类型转换成字符串;——数据存储
从字符串转换为数据类型的过程叫做反序列化;
序列化的目的
![](https://img2018.cnblogs.com/blog/1335019/201902/1335019-20190224164630864-1285143356.png)
有关重要的模块:
json:
pickle:
shelve:python3中新出现
各个模块的优缺点:
json:
优点:通用的序列化格式,其他语言也能够识别。
缺点:只有很少的一部分数据类型能够通过json转换成字符串,比如集合就不行
pickle:
所有的python中的数据类型都可以转换成字符串形式
pikle序列化的内容只有python能够理解
且反序列化依赖代码。一般在游戏开放的时候用的比较多:比如在电脑上玩游戏的过程中,中途退出,那么游戏会软件会把目前游戏中的角色状态数据全部以pikle形式保存起来(完成序列化过程),下次开机后打开游戏,即可加载这些数据(反序列化过程)
shelve:
序列化句柄,
使用句柄直接操作非常方便
由于目前出来不久,所以问题较多
json
dumps(序列化方法)loads(反序列化方法):对内存中的数据进行操作,操作完成后数据还保存在内存中
只有数字,字符串、列表、字典、元组(转换成列表进行序列化)这几种数据类型才能序列化
import json dic={'k':'v'} print(dic,type(dic)) str_d=json.dumps(dic)#序列化 print(str_d,type(str_d)) dic_d=json.loads(str_d)#反序列化 print(dic_d,type(dic_d)) D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/练习.py {'k': 'v'} <class 'dict'> {"k": "v"} <class 'str'>#注意这里k和v都是双引号,在json中字符串如果外面是单引号,里面的内容就是双引号 {'k': 'v'} <class 'dict'> Process finished with exit code 0
元组
import json dic=(1,2,3)#注意这里面的元素只能是数字,不能含有字母,否则报错 print(dic,type(dic)) str_d=json.dumps(dic)#序列化 print(str_d,type(str_d)) dic_d=json.loads(str_d)#反序列化 print(dic_d,type(dic_d)) D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/练习.py (1, 2, 3) <class 'tuple'> [1, 2, 3] <class 'str'> [1, 2, 3] <class 'list'> Process finished with exit code 0
dump和load:对文件进行操作
import json dic={'k1':'v1','k2':'v2'} f=open('fff','w',encoding='utf-8') res1=json.dump(dic,f)#将dic写入文件‘fff'中 f.close()
load:将文件中的内容提却出来
import json
f=open('fff',encoding='utf-8') res2=json.load(f) print(res2,type(res2)) f.close() D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/练习.py {'k1': 'v1', 'k2': 'v2'} <class 'dict'> Process finished with exit code 0
中文的编码
import json dic={'k1':'中国','k2':'v2'}#注意这里如果文件中含有中文,那么最后在文件中显示的中文就是bytes类型 f=open('fff','w',encoding='utf-8') res1=json.dump(dic,f,ensure_ascii=False)#ensure_ascii默认是ture,当修改为False的时候文件中内容就修改过来了 f.close()
json是一次写入,然后全部读出
import json # dic={'k1':'中国','k2':'v2'}#注意这里如果文件中含有中文,那么最后在文件中显示的中文就是bytes类型 # f=open('fff','w',encoding='utf-8') # json.dump(dic,f,ensure_ascii=False) # json.dump(dic,f,ensure_ascii=False)#写入两遍 # f.close() f=open('fff',encoding='utf-8') res1=json.load(f) res2=json.load(f) print(res1,type(res1)) print(res2,type(res2)) f.close()
比如上面的代码就是一次写入太多,但是无法读出,报错
但是一般在写程序的时候应该避免一次性读入太多数据,进而引起内存崩溃,所以需要逐条写入,逐条读出:可以使用以下代码:
import json # l=[{'k1':'111'},{'k2':'111'},{'k3':'111'}] # f=open('fff','w',encoding='utf-8') # for dic in l: # str_d=json.dumps(dic) # f.write(str_d+'\n')#注意必须加上‘\n’来实现换行 # f.close() f=open('fff',encoding='utf-8') l=[] for dic in f: dic_d=json.loads(dic) l.append(dic_d) f.close() print(l)
JSON相关参数说明
Serialize obj to a JSON formatted str.(字符串表示的json对象) Skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。) If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). indent:应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。 default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. sort_keys:将数据根据keys的值进行排序。 To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.
json的格式化输出
就是像网页源代码那样错落有致的输出结果
import json data = {'username':['李华','二愣子'],'sex':'male','age':16} json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)#indent是首行缩进的字符数,indent=2表明首行缩进2个字符; # separators是分隔符, print(json_dic2,type(json_dic2)) D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/练习.py { "age":16, "sex":"male", "username":[ "李华", "二愣子" ] } <class 'str'> Process finished with exit code 0
pikle
pikle也有dumps,loads;dunp,load四种方法,但是它可以包含所有数据类型
dumps,loads
import pickle dic={'k1':'111','k2':'111','k3':'111'} str_d=pickle.dumps(dic) print(str_d,type(str_d))#需要注意的是这里得到的是一个bytes的数据类型 dic_d=pickle.loads(str_d) print(dic_d)
dunp,load
import pickle # dic={'k1':'111','k2':'111','k3':'111'} # f=open('fff','wb')#需要注意的是这里是wb形式 # pickle.dump(dic,f) # f.close() f=open('fff','rb')#需要注意的是这里是rb形式 dic_d=pickle.load(f) print(dic_d) f.close()
但是利用pikel能够实现多行写入,多行读出
import pickle import time # struct_time1=time.localtime(10000000) # struct_time2=time.localtime(10000000) # f=open('fff','wb') # pickle.dump(struct_time1,f) # pickle.dump(struct_time2,f) # f.close() f=open('fff','rb') str_d1=pickle.load(f) str_d2=pickle.load(f) print(str_d1) print(str_d2) f.close()
序列化和反序列化需要有相同的环境。
shelve
只提供了open 方法,open方法获取了一个文件句柄,在操作上和字典类似。