序列化模块
什么叫序列化——
将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化。
什么叫反序列化-——
将序列化后的内容转换回来的过程就叫做 反序列化
为什么要序列化——
1,以某种存储形式使自定义对象持久化
2,将对象从一个地方传递到另一个地方
3,使程序更具维护性
序列化的最终目的就是为了保存下来(比如以文件形式存在硬盘上),或者是发送出去(比如通过网络发送一个类到服务器上),但是文件是没有字典这个概念的,所以我们只能将字典转化成字符串放到文件中。
为什么反序列化不使用eval()——
eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。
BUT!强大的函数有代价。安全性是其最大的缺点。
想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。
而使用eval就要担这个风险。
json模块
所有语言都通用,他能序列化的数据是有限的:
序列化中的内容只能包含:字典 列表 数字 字符串,如果是元祖——自动转成列表的样子
json模块提供了四个功能:dumps,dump,loads,load
#dumps()和loads() ret = json.dumps({"k1":"k2"})#序列化,将字典变成了字符串 print(repr(ret),type(ret))#'{"k1": "k2"}' <class 'str'> ret2 = json.dumps((1,2,3))#'[1, 2, 3]' <class 'str'> print(repr(ret2),type(ret2)) ret2=json.loads(ret)#反序列化,将字符串格式的字典转换为数据结构,字符串只能包含一个数据结构,但是这个数据结构可以嵌套 print(repr(ret2),type(ret2))#{'k1': 'k2'} <class 'dict'> #dump()和load() #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件 # load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回 f = open("json_1","w") dic={"k1":"k2"} json.dump(dic,f) # 这么写进去是没有办法换行的,再使用load()反序列化时,就会报错 json.dump((1,2,3,4,5),f) f.close() f = open("json_1") dic2=json.load(f)#把文件中的内容转换成数据结构返回 f.close() print(dic2) #当文件中每一行都是一个数据结构时,可以读取其中的每一行 f=open("json_1","r") for i in f: print(json.loads(i)) f.close() # f1=open("json_1","w") str = json.dumps({"k2":"v2"}) f1.write(str+"\n")#追加时注意换行符的位置,要判断换行符在前还是在后 f1.close()
json的dumps()
json.dumps()会将回将内部字符装换成编码,将ensure_ascii参数设置为False就能变回原字符
>>> import json >>> json.dumps("魏文刚") '"\\u9b4f\\u6587\\u521a"' >>> json.dumps("魏文刚",ensure_ascii=False) '"魏文刚"'
自定义序列化规则
import datetime import json dic = { 'k1':123, 'ctime':datetime.datetime.now() } class MyEncoder(json.JSONEncoder): def default(self, o): # o是数据类型 if isinstance(o,datetime.datetime): return o.strftime('%Y-%m-%d') else: return super(MyEncoder,self).default(o) v = json.dumps(dic,cls=MyEncoder) print(v) # {"k1": 123, "ctime": "2018-05-15"}
pickle模块
pickle是python特有的,能够序列化任何数据类型(包括对象),python专有的不能和其他语言兼容,结果是bytes
方法和json一样,dumps,loads,dump,load
读写文件时,要用b模式
import pickle ret = pickle.dumps({"k":"v"}) print(ret) #b'\x80\x03}q\x00X\x01\x00\x00\x00kq\x01X\x01\x00\x00\x00vq\x02s.' #用pickle序列化的类型,反序列化也必须用pickle
pickle模块再向文件中写时不用换行,读的时候每次读一个数据类型
import pickle f = open("a","wb") dict = {"用户名":178973,"用户名2":21324325} pickle.dump(dict,f) pickle.dump([1,2,3,4,5,6],f) f.close() f = open("a","rb") print(pickle.load(f)) print(pickle.load(f)) #{'用户名': 178973, '用户名2': 21324325} #[1, 2, 3, 4, 5, 6]
shelve模块
只限于python语言,能转换所有的数据类型,只有一种使用方法,使用方法类似于字典
shelve 只提供一个open,shelve.open('文件名')拿到一个文件句柄,这个文件句柄就可以当做字典操作
正常情况下shelve打开的文件句柄感知不到值的修改,设置writeback = True就可以保存修改内容了
flag参数
flag=c 默认参数,打开文件进行读写,必要时创建该文件
flag=w 打开文件进行读写,如果文件不存在,不会创建他
flag=n 打开文件进行读写,但总创建一个新的空白文件
import shelve f = shelve.open('shelve_file') f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'} #直接对文件句柄操作,就可以存入数据 f.close() import shelve f1 = shelve.open('shelve_file') existing = f1['key'] #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错 f1.close() print(existing) #结果 #{'int': 10, 'float': 9.5, 'string': 'Sample data'}
修改
f=shelve.open("222") print(f["q"]) f["q"].append("c") print(f["q"]) f.close() # f=shelve.open("222",writeback=True) print(f["q"]) f["q"].append("a") print(f["q"]) f.close() #运行结果 #[1, 2, 3, 4, 5] #[1, 2, 3, 4, 5] #[1, 2, 3, 4, 5] #[1, 2, 3, 4, 5, 'a']