序列化模块

将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化

导引

比如,我们在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、在向文件里面写内容的时候就需要将字典等数据类型转换成字符串;——数据存储
从字符串转换为数据类型的过程叫做反序列化;

序列化的目的

1、以某种存储形式使自定义对象持久化
2、将对象从一个地方传递到另一个地方。
3、使程序更具维护性。

 

有关重要的模块:

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方法获取了一个文件句柄,在操作上和字典类似。

 

posted @ 2019-02-21 22:45  舒畅123  阅读(128)  评论(0编辑  收藏  举报