Python学习笔记:序列化(Serialize)和反序列化(Deserialize)
1、使用场景一:保存内存中的数据到文件中,然后在下次要使用的时候再反序列化恢复数据,这样使临时中断的工作得已恢复。比如虚拟机的快照等。
2、使用场景二:可以将数据序列化以后在两种不同的语言中传输,比如Python数据类型转成json格式再传给Java
3、注意:json包只支持字典格式,作用是在不同语言程序之间进行数据交换,而pickle包则支持所有的python数据高效率的数据序列化,但因为python数据类型不能在不同的语言间通用所以只能python内部使用。
例1:这是一个最简单的序列化和反序列化的例子,使用eval()还原这个字典dict1
dict1 = {"name":"tangwei","age":"18","profession":"professional"}
file1 = open("test.txt","w",encoding="utf-8")
file1.write(str(dict1)) # 文件中只能存字节型或者字符型
file1.close()
file1 = open("test.txt","r")
lines = file1.readlines()
file1.close()
for line in lines:
dict2 = eval(line) # 这仅仅是读取文本,但是要放在内存中执行,还需要用到eval(),让python把字符串当成代码来执行
print("姓名",dict2["name"])
例2:以上代码并非通用方法,因为eval()只在python使用,如果要再多语言中传送和转化数据可以用到json
import json
dict1 = {"name":"tangwei","age":"18","profession":"professional"}
file1 = open("test.txt","w",encoding="utf-8")
file1.write(json.dumps(dict1)) # 文件中只能存字节型或者字符型,用dumps序列化,与json.dump(dict1,file1)功能一样
file1.close()
file1 = open("test.txt","r")
# json_obj = json.load(file1) # 可以用load更简便,也可以用下面的for循环
# print("姓名", json_obj["name"])
# 将读出的字符串转换成json格式
for line in file1:
json_obj = json.loads(line) # 用loads反序列化
print("姓名", json_obj["name"])
file1.close()
例3:那么能不能将一个函数也序列化呢?如果能将函数和类都序列化,那么我再次取出的时候就可以直接恢复到中断时的状体,岂不是美滋滋?
# 注意:python的json包不能将函数和类对象之类的序列化,只能序列化字符和字节型数据。
import json
def test1(name):
print("111",name)
dict1 = {"name":"tangwei","age":"18","method":test1}
file1 = open("test.txt","w",encoding="utf-8")
file1.write(json.dumps(dict1)) # 用dumps序列化只能是字节型或者字符型,test1是函数的内存地址,不能序列化,所以这里会报错!
file1.close()
例4:如果一定要将函数序列化,那么只能用pickle包。
import pickle
def test1(name):
print("111",name)
dict1 = {"name":"tangwei","age":"18","method":test1}
file1 = open("test.txt","wb") # 这里要用wb,写字节类型
file1.write(pickle.dumps(dict1))
file1.close()
file1 = open("test.txt","rb")
# 将读出的字符串转换成json格式
for line in file1:
# 用loads反序列化
json_obj = pickle.loads(line)
print("姓名", json_obj["name"])
# 可以直接执行同名函数,注意,这里的test1已经不是原来的test1了,因为序列化以后test1就释放了
json_obj["method"]("tangwei")
file1.close()
例5:实例化一个类的对象,使用追加“ab”模式,将同类对象序列化到一个文件中,取出的时候用下“yield”生成器取出对象。
import pickle class MyPickle(object): def __init__(self, file_name): self.file_name = file_name def dump(self, obj): """ 序列化对象 :param obj: :return: """ with open(self.file_name, 'ab') as f: pickle.dump(obj, f) print('dump data', obj.__dict__) def loaditer(self): """ 迭代反序列化对象 :return: """ f = open(self.file_name, 'rb') while True: try: obj = pickle.load(f) yield obj except EOFError: print('EOFError') f.close() print(f.closed) break class Person: def __init__(self, n, a): self.name = n self.age = a def show(self): print(self.name + "_" + str(self.age)) aa = Person("aGood", 2) bb = Person("bGood", 3) cc = Person("cGood", 4) p = MyPickle('c.txt') p.dump(aa) p.dump(bb) p.dump(cc) iter_obj = p.loaditer() while True: try: print(next(iter_obj).__dict__) except StopIteration: print('stop') break
例6:一个简单的将类实例化的例子,但是这里如果用“ab”追加模式,每次反序列化的时候只能取得第一个对象
class DataPickle: def __init__(self, file, obj): self.file = file self.obj = obj def dump(self): f = open(self.file, 'wb') pickle.dump(self.obj, f) def load(self): f = open(self.file, 'rb') return pickle.load(f).__dict__ class School: def __init__(self,name): self.name = name input_val = input("请输入学校地址:") school = School(input_val) dp = DataPickle("data.txt", school) dp.dump()
推荐写法1:一次性写或者读,不用for循环一行行操作用load或者dump,用with不用考虑关闭文件的问题
import json
file_path="文件路径"
account_data = {“name”:"tangwei","age":18}
# 写文件
with open(file_path, 'w') as f:
json.dump(account_data,f)
# 读文件
with open(file_path,'r') as f:
account_data= json.load(f)
推荐写法2:因为json和pickle只支持序列化后的文件中只有一个json数据结构,如果有多个单独的字典或者多个列表要存入就需要归结成一个后存入,而且每次更新文件数据也是删除旧数据重新写如,很不方便,这时候可以用shelve包,支持任意类型任意存储更新。
import sys,shelve,time,json d = shelve.open("shelve_test") info = {"age":22,"job":"it"} name = ["tangwei","chenyadan"] # 存入数据 d["name"] = name d["info"] = info d["date"] = time.time() d.close() # 读取数据 d = shelve.open("shelve_test") print(d.get("name")) print(d.get("info")) print(d.get("date")) # 更新数据 d.update({"name":"chenmeifan"}) d.update({"info":"你好"}) d.update({"date":time.ctime(time.time())}) d.close() #读取新数据 d = shelve.open("shelve_test") print("新数据",d.get("name")) print("新数据",d.get("info")) print("新数据",d.get("date")) d.close()