一、什么是模块
常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
但其实import加载的模块分为四个通用类别:
1 使用python编写的代码(.py文件)
2 已被编译为共享库或DLL的C或C++扩展
3 包好一组模块的包
4 使用C编写并链接到python解释器的内置模块
为何要使用模块?
如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。
随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用。
二、序列化模块
什么叫序列化——将原本的字典、列表等内容转换成一个字符串或者bytes的过程就叫做序列化
比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给?
现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来。
但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中。
你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢?
没错序列化的过程就是从dic 变成str(dic)的过程。现在你可以通过str(dic),将一个名为dic的字典转换成一个字符串,
但是你要怎么把一个字符串转换成字典呢?
聪明的你肯定想到了eval(),如果我们将一个字符串类型的字典str_dic传给eval,就会得到一个返回的字典类型了。
eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。
BUT!强大的函数有代价。安全性是其最大的缺点。
想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。
而使用eval就要担这个风险。
所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)
为什么要有序列化模块?
数据结构转化成这个特殊的序列有什么用呢? 这个才是序列化的关键所在,这个特殊的序列大有用处。举例说明:
比如,你的程序中需要一个字典类型的数据存放你的个人信息:
dic = {
'username':'山药', 'password': 123456,'login_status': True}
你的程序中有一些地方都需要使用这个dic数据,登录时会用到,注册时也会用到。那么我们之前就是将这个dic写在全局里,但是这样是不合理的,应该是将这数据写入一个地方存储(还没有学数据库),现在先存放在一个文件中,那么程序中哪里需要这个数据了,你就读取文件取出你需要的信息即可。那么有没有什么问题? 你将这个字典直接写入文件是不可以的,必须转化成字符串的形式,而且你读取出来也是字符串形式的字典。
那么你拿到一个str(dic)有什么用?他是根本转化不成str的(不能用eval很危险),所以很不方便。那么这时候序列化模块就起到作用了,如果你写入文件中的字符串是一个序列化后的特殊的字符串,那么当你从文件中读取出来,是可以转化回原数据结构的。这个就很牛逼了。
下面说的是json序列化,pickle序列化有所不同:
json序列化除了可以解决写入文件的问题,还可以解决网络传输的问题,比如你将一个list数据结构通过网络传给另个开发者,那么你不可以直接传输,之前我们说过,你要想传输出去必须用bytes类型。但是bytes类型只能与字符串类型互相转化,它不能与其他数据结构直接转化,所以,你只能将list —> 字符串 —> bytes 然后发送,对方收到之后,在decode() 解码成原字符串。此时这个字符串不能是我们之前学过的str那种字符串,因为它不能反解,必须要是这个特殊的字符串,他可以反解成list ,这样开发者之间就可以借助网络互传数据了,不仅仅是开发者之间,你要借助网络爬取数据这些数据多半是这种特殊的字符串,你接受到之后,在反解成你需要的数据类型。
对于这个序列化模块我们做一个小小总结:
序列化模块就是将一个常见的数据结构转化成一个特殊的序列,并且这个特殊的序列还可以反解回去。它的主要用途:文件读写数据,网络传输数据。
Python中这种序列化模块有三种:
-
json模块 : (重点)
- 不同语言都遵循的一种数据转化格式,即不同语言都使用的特殊字符串。(比如Python的一个列表[1, 2, 3]利用json转化成特殊的字符串,然后在编码成bytes发送给php的开发者,php的开发者就可以解码成特殊的字符串,然后在反解成原数组(列表): [1, 2, 3])
- json序列化只支持部分Python数据结构:dict,list, tuple,str,int, float,True,False,None
-
pickle模块:
- 只能是Python语言遵循的一种数据转化格式,只能在python语言中使用。
- 支持Python所有的数据类型包括实例化对象。
-
shelve模块:类似于字典的操作方式去操作特殊的字符串
序列化的目的
- 以某种存储形式使自定义
- 将对象从一个地方传递到另一个地方
- 使程序更具维护性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRgtuC69-1598951530859)(…/…/Typora/Image/image-20200830141634043.png)]
Python可序列化的数据类型
| Python | JSON |
| dict | object |
| list, tuple | array |
| str | string |
| int, float | number |
| True | true |
| False | false |
| None | null |
2.1 json模块
Json模块提供了四个功能:dumps、dump、loads、load
用于网络传输:dumps、loads
import json
dic = {
'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic) # 序列化:将一个字典转换成一个字符串
print(type(str_dic),str_dic)
'''
<class 'str'> {"k1": "v1", "k2": "v2", "k3": "v3"}
# 注意,json转换完的字符串类型的字典中的字符串是由""表示的
'''
dic2 = json.loads(str_dic) # 反序列化:将一个字符串格式的字典转换成一个字典
print(type(dic2),dic2)
'''
<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
#注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示
'''
list_dic = [1,['a','e','f'],3,{
'k1':'v1','k2':'v2','k3':'v3'}]
str_dic2 = json.dumps(list_dic) #也可以处理嵌套的数据类型
print(type(str_dic2),str_dic2)
'''
<class 'str'> [1, ["a", "e", "f"], 3, {"k1": "v1", "k2": "v2", "k3": "v3"}]
'''
list_dic2 = json.loads(str_dic2)
print(type(list_dic2),list_dic2)
'''
<class 'list'> [1, ['a', 'e', 'f'], 3, {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}]
'''
用于文件写读:dump、load
import json
f = open('json_file',mode='w',encoding='utf-8')
dic = {
'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f) # dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()
f = open('json_file')
dic2 = json.load(f) # load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
f.close()
print(type(dic2),dic2)
其他参数说明
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的中文即可正常显示。)
- indent:应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json
- separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。
- sort_keys:将数据根据keys的值进行排序。
import json
data = {
'username':['尼古拉斯赵4','杨把总'],'sex':'male','age':'18'}
json_dic = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)
print(json_dic)
'''
{
"age":"18",
"sex":"male",
"username":[
"尼古拉斯赵4",
"杨把总"
]
}
'''
json序列化存储多个数据到同一个文件中
对于json序列化,存储多个数据到一个文件中是有问题的,默认一个json文件只能存储一个json数据,但是也可以解决,举例说明:
import json
dic1 = {
'name':'lisi'}
dic2 = {
'subject':'Python'}
dic3 = {
'age':'18'}
f = open('mul_json',mode='a',encoding='utf-8')
json.dump(dic1,f)
json.dump(dic2,f)
json.dump(dic3,f)
f.close()
f = open('mul_json',encoding='utf-8')
json_dic = json.load(f)
json_dic2 = json.load(f)
json_dic3 = json.load(f)
print(type(f),json_dic)
上面会报错
解决办法:
import json
dic1 = {
'name':'lisi'}
dic2 = {
'subject':'Python'}
dic3 = {
'age':'18'}
f = open('mul_json',mode='a',encoding='utf-8')
str1 = json.dumps(dic1)
f.write(str1+'\n')
str2 = json.dumps(dic2)
f.write(str2+'\n')
str3 = json.dumps(dic3)
f.write(str3+'\n')
f.close()
f = open('mul_json',encoding='utf-8')
for line in f:
print(json.loads(line))
'''
{'name': 'lisi'}
{'subject': 'Python'}
{'age': '18'}
'''