序列化模块
序列化模块
什么是序列化?
序列化就是把对象的信息和状态转化为可以存储或传输的过程, 通俗来讲就是把内存中的对象转换为字符串或字节的过程,在Python中叫pickling。
为什么要序列化?
json
要在不同语言之间传递对象,就必须要转化为标准通用的格式,json格式就是很好的选择,它本身就是字符串,很容易在网络中传输和被其他语言解析,再加上json简洁清晰,json更是不二的选择。
Python内置的json模块就能方便的把一些Python对象转化为json格式。
json模块主要提供了4个方法: 序列化 dump(), dumps(), 反序列化 load(), loads()
json通过dumps()将对象序列化为字符串和loads()将序列化后对象反序列化恢复原本的对象
import json dic = dict(k1='v1', k2='v2', k3='v3', k4='v4') # 创建字典对象 json_dic = json.dumps(dic) # 序列化字典,返回字符串 print('str', str(dic)) # 打印调用字符串强转字典的输出结果 print('json', json_dic) # 打印json序列化后的输出结果 json_str = '{"k1": "v1", "k2": "v2", "k3": "v3", "k4": "v4"}' # 定义一个json字符串 dic2 = json.loads(json_str) # 反序列化json字符串,这里返回字典对象 print(type(dic2), dic2) # 打印转化后的对象类型和对象信息
str {'k2': 'v2', 'k4': 'v4', 'k1': 'v1', 'k3': 'v3'}
json {"k2": "v2", "k4": "v4", "k1": "v1", "k3": "v3"}
<class 'dict'> {'k2': 'v2', 'k4': 'v4', 'k1': 'v1', 'k3': 'v3'}
json通过dump()将对象序列化为字符串然后写进文件和load()从文件读取内容反序列化恢复原本的对象
import json dic = dict(k1='v1', k2='v2', k3='v3', k4=[1, 2, 3]) # 创建字典对象 with open('json_test.txt', 'w') as f: # 创建一个f文件句柄 json.dump(dic, f) # load方法将对象直接序列化写进文件 # json.dump([1, 2, 3, 4], f) with open('json_test.txt') as f: # 创建文件句柄 dic_obj = json.load(f) # 重新从文件反序列化对象返回 print(type(dic_obj), dic_obj) # 打印输出结果和类型
但是load方法有缺陷,一次只能读出一个对象,当有多个对象分别序列化到文件中,反序列化就会报错,遇到这种问题一般都现在内存中序列化对象,然后一行一行主动写进文件中,如下所示
import json dic = dict(age=12, name='小明', score=77) # 创建字典对象 dic2 = dict(age=12, name='小红', score=89) # 创建字典对象 dic3 = dict(age=14, name='小王', score=91) # 创建字典对象 li = [dic, dic2, dic3] f = open('json_test.txt', 'w') for dic in li: json_str = json.dumps(dic, ensure_ascii=False) # ensure_ascii=False使输出到文件中是中文,而不是\u xxx f.write(json_str + '\n') f.close() f = open('json_test.txt') for json_str in f: dic = json.loads(json_str) # 写入文件是一行一个对象,读入也按这个规则解析 print(dic)
{'age': 12, 'name': '小明', 'score': 77}
{'age': 12, 'name': '小红', 'score': 89}
{'age': 14, 'name': '小王', 'score': 91}
json的定制序列化对象
json的序列化只支持很少的数据类型序列化,像自定义的类,集合等就不能序列化,所以要自己定制json序列化的对象。
通过官方文档可以了解json可以自己定制json序列化的对象。下面是dumps的函数原型,有一大堆可选参数。
json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
其中default参数描述是这样的:
If specified, default should be a function that gets called for objects that can’t otherwise be serialized. It should return a JSON encodable version of the object or raise a TypeError. If not specified, TypeError is raised.
大意是default应该是一个函数供不能被序列化的对象调用,而且该函数返回可以序列化为Json的对象或抛出一个异常。
下面是一个应用,把自定义对象转化为JSON可以解析的字典对象
import json class Person(object): def __init__(self, name, age, country): self.name = name self.age = age self.country = country def __repr__(self): return '<class Person> name=%s, age=%d, country=%s' % (self.name, self.age, self.country) def person_to_dict(person): return dict( name=person.name, age=person.age, country=person.country ) p = Person('小明', 12, '中国') print(p) # json_str = json.dumps(p, default=person_to_dict, ensure_ascii=False) # 也可以直接一个lambda表达式搞定 json_str = json.dumps(p, default=lambda p: dict(name=p.name, age=p.age, country=p.country), ensure_ascii=False) print(json_str)
<class Person> name=小明, age=12, country=中国 {"age": 12, "name": "小明", "country": "中国"}
pickle
pickle和json一样提供了4个接口序列和反序列化,不过pickle是把Python的任意对象序列化为bytes类型。
import pickle student = {'name': '小明', 'age': 12} pickle_str = pickle.dumps(student) # 序列化为字节类型 print('student:', student) # 打印student的信息 print('pickle:', pickle_str) # 打印序列化后的信息 with open('test_pickle.txt', 'wb') as f: f.write(pickle_str) # 写进文件, 在文件中查看是一堆乱码 with open('test_pickle.txt', 'rb') as f: s = pickle.loads(f.read()) # 反序列化 print('student:', s) # 数据也成功还原了
student: {'age': 12, 'name': '小明'}
pickle: b'\x80\x03}q\x00(X\x03\x00\x00\x00ageq\x01K\x0cX\x04\x00\x00\x00nameq\x02X\x06\x00\x00\x00\xe5\xb0\x8f\xe6\x98\x8eq\x03u.'
student: {'age': 12, 'name': '小明'}
pickle也可以直接dump任意对象到文件,然后读出来,而且也没有了json的load的缺陷。
import pickle import time t1 = time.localtime() t2 = time.localtime(1.5e10) with open('test_pickle.txt', 'wb') as f: # 因为pickle是二进制写进文件的,所以也要用二进制方式读写 pickle.dump(t1, f) # 任意对象序列化 pickle.dump(t2, f) with open('test_pickle.txt', 'rb') as f: t1 = pickle.load(f) t2 = pickle.load(f) print(t1) print(t2)
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=24, tm_hour=10, tm_min=11, tm_sec=15, tm_wday=5, tm_yday=328, tm_isdst=0)
time.struct_time(tm_year=2445, tm_mon=5, tm_mday=1, tm_hour=10, tm_min=40, tm_sec=0, tm_wday=0, tm_yday=121, tm_isdst=0)
小结: pickle很强大,能序列化任意对象,而json默认只能序列化少数内置对象(需要自己实现定制),但是pickle只能用于python,序列化后的数据别的语言就不能反序列化了,甚至不同版本的python也可能不能兼容。选择用哪种方式序列化对象就看自己的需求了。
参考:

浙公网安备 33010602011771号