json模块
1.序列化
1.1为什么有数据类型
数据类型:为了让计算机认识,更好的数据数据
数据类型是不同业务场景对组织数据的合理抽象,例如队列就是对现实中排队办业务的抽象,栈则是对类似于现实中下象棋悔棋,只能一步一步的悔,总不能说,这些不算我把刚开局的炮挪一下,其他的我不动!
针对不同的业务场合而抽象出来的数据类类型是为了让我们的数据在内存中计算的更加高效,存放的更加有规律可循.
但是数据类型并不可以作为数据直接存储,也不可以作为传输来使用.
必须都是变成二进制来存储或传输.
数据类型----->str的过程叫做序列化,之后encoding为二进制,作为数据传输的方式或者存放到硬盘中.
1.2python序列化
#提供了json,pickle,shelve(几乎不用)三个序列化模块 #json,多种语言通用的格式 #dumps:数据类型->str #loads:str->数据类型
#dumps 和 loads都是在内存中玩,至于后续你要写到文件还是网络传输看需求而定
#需要写到本地硬盘,就开文件句柄把数据写入硬盘
#将硬盘中序列化的数据读到内存中可以一次性读到内存,但是还要后续的str拆分工作,然后才能反序列化为数据类型,无法一次性将含有多个数据类型形式的str直接反序列化
#和文件有关的两个方法,先要有文件句柄 #dump:数据类型->文件 #load:文件->数据类型,load不能多次load
加s的方法dumps loads操作完的数据还在内存中,可以用于网络传输或者存放到硬盘中
不加s的方法dump load则是和文件句柄打交道,用于与硬盘交互,
但是文件里面的数据如果一次性读进来,那么这个数据必须且只能是一个数据类型,如一个字典,如果是多个字典不可以
因此使用dump 和load时如果文件里面是多个数据类型的str,最好一个数据类型占一行,一行一行的转为数据类型.
1.3注意事项
- json只认识list str int dict因为几乎所有语言都识别这些形式的数据,且dict的key必须是str,如果数字作为key,那么会强制的变为str,如果元组做value序列化强制变为list,反序列化则是变为list,因为其他语言不认识元组.
{"k": 1, "v": 2, "1": ["zhangsan", "lisi"], "stu_msg": {"name": "zhangsan", "age": 23, "teachers": ["math", "music", "eng"]}} <class 'str'> {'k': 1, 'v': 2, '1': ['zhangsan', 'lisi'], 'stu_msg': {'name': 'zhangsan', 'age': 23, 'teachers': ['math', 'music', 'eng']}} <class 'dict'>
#可见无论怎么嵌套,理论都是不变的,tuple变list
1.4实例
再次强调,dumps和loads都是在内存中玩,内存还是硬盘,str还是数据类型写的时候要十分的清晰
dump和load面向的是单个文件,里面多数情况下是多个字典形式,因此用复数
dumps和loads面向的是多个数据类型组成的一个数据类型,因此用单数
import json #加s的方法操作完的数据还在内存中,用于网络传输 myDict = {"k":1,"v":2,1:("zhangsan","lisi")} myStr = json.dumps(myDict) print(myStr,type(myStr)) new_str=json.loads(myStr) print(new_str,type(new_str))
将数据写到文件中
import json # 加s的方法操作完的数据还在内存中,用于网络传输 myDict = myDict = {
'k':1,
"v":2,
1:("zhangsan","lisi"),
"stu_msg":{"name":"zhangsan","age":23,"teachers":("math","music","eng")}}
myStr = json.dumps(myDict)
print(myStr,type(myStr)) with open("json.info","w",encoding="utf8") as ff: json.dump(myStr,ff)
读的时候,操作文件句柄读到内存中是str,想要转为数据类型还是要json.loads()一下的
import json # 加s的方法操作完的数据还在内存中,用于网络传输 myDict = myDict = {'k':1,"v":2,1:("zhangsan","lisi"),"stu_msg":{"name":"zhangsan","age":23,"teachers":("math","music","eng")}} myStr = json.dumps(myDict) print(myStr,type(myStr)) with open("json.info",encoding="utf8") as f2: msg = json.load(f2) print(msg,type(msg)) dict_msg = json.loads(msg) print(dict_msg,type(dict_msg))
2. pickle模块
方法和json一模一样,只不过它识别所有的python数据类型
但是接收方必须也有pickle模块才能对接收的数据进行解析
它序列化之后的str都是二进制,所以操作的文件句柄的mode必须加上b如"wb""ab""rb"
3.最佳实践
三方面:磁盘IO 内存 可操作性
无论序列化之后写入文件,还是反序列化读入内存,尽量不要直接dump和load
数据类型-->str后,dump到文件中是不好的,即使dump到文件多个数据类型str,并不会加换行符,为反序列化造成麻烦,
内存中数据序列化到硬盘最好是write写到文件,加上换行符,方便反序列化时的可操作性
反序列化时,不要直接load文件句柄,当文件很大时会瞬间把磁盘IO和内存打满,性能急剧下降,无法处理其他请求,即使处理的很快,一旦此时有用户访问服务器,会造成很高的延迟
而是采用loads的方式一行一行的反序列化,保证内存中只有一行str的反序列化之后的数据类型,这样IO不会瞬间被打满,内存中处理一行数据没有指向之后被GC回收,保证内存中只有一个变量名指向每行的数据类型.