序列化模块汇总
一、序列和序列化的区别:
- 序列:在python中序列包括字符串、列表、元组,通常情况下可以被下标索引的数据类型才能被称为序列
- 序列化:序列化中的序列定义非常狭义,只包括字符串。把一个类型转换成字符串的过程被称为序列化
- 反序列化:从文件中读取数据并转换成原有格式的过程被称为反序列化
二、为什么要使用序列化(适用情形):
- 把内容写入文件,文件存储都是以字符串的格式进行
- 网络传输数据,网线-->电压-->二进制文件-->bytes-->字符串,把字符串转换成bytes就可以进行网络传输来了。
三、json模块
json可以处理的数据格式:ture、false、null、 字典、元组、列表和数值,元组序列化时会被强制转换成列表格式
- 在python中没有单双引号的强制要求,但是当使用json模块把数据类型转换成json格式后,数据类型中的单引号被强制转换成双引号,json不支持单引号。
- 序列化:
- json.dumps(数据):在单个数据转换的时候使用
- json.dump(数据,文件句柄):通过文件句柄写入文件时使用
- 反序列化:
- json.loads(字符串):把单个json格式的数据转换成原有格式时使用
json.load(文件句柄):把文件中的json格式数据转换成原有格式时使用
注意:dumps和loads都是直接和内存打交道,dump和load直接和文件打交道。
import json list = [1,3,4,5,654,'dsf'] str_list = json.dumps(list) # 序列化 print([str_list], type(str_list)) list1 = json.loads(str_list) # 反序列化 print(list1) with open('json_dump', mode='w') as f: json.dump(list, f) # json写入文件 with open('../第三方库/json_dump', mode='r') as f: print(json.load(f)) # 反序列化读取文件 dict = {1:2,3:4,5:6} str_dict = json.dumps(dict) print(str_dict) new_dict = json.loads(str_dict) print(new_dict) ''' 结果是: ['[1, 3, 4, 5, 654, "dsf"]'] <class 'str'> [1, 3, 4, 5, 654, 'dsf'] [1, 3, 4, 5, 654, 'dsf'] {"1": 2, "3": 4, "5": 6} # key值直接加上了双引号 {'1': 2, '3': 4, '5': 6} # 转换回来的key也加上了单引号 '''
- json格式的限制:
- 字典中json格式的key必须是字符串类型,如果不是,json.dumps/dump会强行转换成字符串类型
- 字典序列化时支持元组做value,转换后value为列表类型,反序列化后也是列表类型,不再是元组,并且
json转换中不支持元组作为字典的key来使用。 - 集合不能被dumps/dump,即不能被序列化
- 自己许写的json格式的文件中字符串必须时双引号,不能是单引号,如果是单引号,那么反序列化时会报错。
dict = {1:2,3:4,5:6} str_dict = json.dumps(dict) print(str_dict) new_dict = json.loads(str_dict) print(new_dict) dict1 = {'key': (1,2,3)} str_dict1 = json.dumps(dict1) print(str_dict1) new_dict1 = json.loads(str_dict1) print(new_dict1) dict2 = {(1,2,3):'key'} str_dict2 = json.dumps(dict2) print(str_dict2) ''' 结果是: {"1": 2, "3": 4, "5": 6} {'1': 2, '3': 4, '5': 6} {"key": [1, 2, 3]} # 序列化时元组被强行转换成列表类型 {'key': [1, 2, 3]} # json反序列化后元组依然被转换成列表形式 TypeError: keys must be str, int, float, bool or None, not tuple # value在json转换序列化时不能作为字典的key使用 '''
- 以json格式写入文件时,可以在一个文件句柄下进行多次dump,但是读取文件时却只能使用一次load,不能多次使用;
如果希望可以在json文件下一个文件句柄多次读取,必须在序列化的时候,在文件句柄下先使用dumps把数据类形转换成json格式,再使用f.write(json数据1+'\n')
f.write(json数据2+'\n')把数据写入文件,在读取时使用for循环,对每一行进行loads。
lst1 = ['12',2, 3, (1,2,3), 2.3] dic1 = {'name': 'alex', 'age': 20} set1 = {1,2,3,4} num = 12343 with open('../第三方库/json_dump', mode='w') as f: str_lst1 = json.dumps(lst1) str_dic1 = json.dumps(dic1) str_num = json.dumps(num) total_str = str_lst1 + '\n' + str_dic1 + '\n' + str_num f.write(total_str) with open('../第三方库/json_dump', mode='r') as f: for line in f: result = json.loads(line) print(result) ''' 结果是: ['12', 2, 3, [1, 2, 3], 2.3] {'name': 'alex', 'age': 20} 12343 '''
- 中文在序列化后默认转换成unicode编码格式,如果希望写入json文件后依然是中文显示,可以在序列化时设置ensure_ascii=False。
如果是写入文件时只设置ensure_ascii=False,文件中会出现乱码,需要在open中规定编码格式为utf-8
'''序列化时的中文转换问题''' dict1 = {'name': 'alex', 'country': '中国'} str_dict1 = json.dumps(dict1) print(str_dict1) # 当序列化时如果不设置,中文默认会被转换成unicode编码格式 str_dict2 = json.dumps(dict1, ensure_ascii=False) print(str_dict2) # 设置ensure_ascii=False序列化后中文依然显示 new_dict1 = json.loads(str_dict1) print(new_dict1) new_dict2 = json.loads(str_dict2) print(new_dict2) # 无论是否显示,反序列化时中文都会正常显示 with open('../第三方库/json_dump', 'a', encoding='utf-8') as f: json.dump(dict1, f, ensure_ascii=False) ''' 结果是: {"name": "alex", "country": "\u4e2d\u56fd"} {"name": "alex", "country": "中国"} {'name': 'alex', 'country': '中国'} {'name': 'alex', 'country': '中国'} '''
- json格式化操作:
格式化并不能在序列化写入文件时使用,转换格式只是为了让开发者/用户看的更清楚。- sort_keys=True, 根据key进行排序
- indent=num,缩进几个空格,num可以根据需要写
- separators=(',', ':'), 分割符,逗号是不同key、value元素之间的分割符,
冒号是key和value之间的分割符。
dict1 = {'name': 'alex', 'country': '中国', 'hobby': ['篮球', '足球', '健身', '劈叉']} new_dict3 = json.dumps(dict1, ensure_ascii=False, indent=2, separators=(',', ':'), sort_keys=True) print(new_dict3) ''' 结果是: { "country":"中国", "hobby":[ "篮球", "足球", "健身", "劈叉" ], "name":"alex" } '''
四、pickle模块
- 用法:pickle.dump/dumps/load/loads()
- pickle可以对类的实例化对象进行序列化操作,json不能对实例化对象进行进行序列化操作
- pickle序列化后的结果是bytes类型,开发者看不懂,json的结果是字符串类型。
- 在执行读写入文件的时候需要用mode='rb/ab/wb',因为序列化的结果是bytes类型
- 在序列化向文件中写入的时候,pickle可以多次dump,而json不能多次dump
- pickle读取多个数据的时候需要用range,json直接遍历句柄f
- pickle不能跨平台,json可以跨平台使用
pickle在序列化和反序列化的时候不会对原有的数据类型进行转换,保留原有的格式,而json会在序列化时对格式进行转换,
而在反序列化是部分原有的数据如元组已经被永久的转换成了列表格式'''pickle模块''' import pickle class Student: COUNTRY = '中国' def __init__(self, name, age): self.name = name self.age = age s1 = Student('维维', 20) s2 = Student('布布', 40) s3 = Student('尔尔', 30) s4 = Student('什什', 28) pickle_s1 = pickle.dumps(s1) print(pickle_s1) # pickle可以对类的对象进行序列化操作,但是json不能对对象进行序列化操作 # with open('../第三方库/pickle_dump', 'wb') as f: # pickle.dump(s2, f) # pickle.dump(s3, f) # pickle.dump(s4, f) with open('../第三方库/pickle_dump', 'rb') as f: for i in range(3): # pickle读取多个数据的时候需要用range,json直接遍历句柄f obj = pickle.load(f) print(obj) print(obj.name) ''' b'\x80\x03c__main__\nStudent\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x06\x00 \x00\x00\xe7\xbb\xb4\xe7\xbb\xb4q\x04X\x03\x00\x00\x00ageq\x05K\x14ub.' <__main__.Student object at 0x110147c10> 布布 <__main__.Student object at 0x11015be90> 尔尔 <__main__.Student object at 0x110147810> 什什 '''
五、shelve模块
- shelve只支持两个语法:shelve.open()/close()
- 通过文件句柄f[key_name] = '需要存入的数据'来写入文件,可以一次读写入多个数据
- 当写入文件后,修改文件会很少,绝大部分是读取操作,并且是通过每一个key来获得的value的情况下才使用shelve
python3对shelve的模块的支持不是很好。
'''shelve模块''' import shelve f = shelve.open('shelve_demo') f['key'] = {'k1': 'v1', 'k2': (1,2,3), 'k3': ['sd', 'as', 'sd']} f['k1'] = [1,2,3,4,5] f.close() f = shelve.open('shelve_demo') content = f['key'] content1 = f['k1'] print(content, content1) ''' {'k1': 'v1', 'k2': (1, 2, 3), 'k3': ['sd', 'as', 'sd']} [1, 2, 3, 4, 5] '''
六、总结
- 当写入文件后需要开发者查看的并且跨平台的数据,使用json模块写入
- 当写入文件给机器看且可以支持类对象的数据,使用pickle模块写入
- 当写入文件是以key、value格式写入的,修改很少,通过key获取value的数据,使用shelve模块来写入