转载自如下文章
###序列化和反序列化
序列化:就是把正在运行中的内存数据存储到硬盘文件的过程,内存中正在运行的数据不管是什么数据类型,都必须先转化为__字符串或者二进制数__。
反序列化:就是序列化的逆运算,把存储到硬盘文件的内容,重新加载到内存中。
##pickle模块##
pickle,用于python特有的类型 和 python的数据类型间进行转换,只能在python语言中使用,无法兼容其他语言。
pickle数据是以二进制形式存储的。
pickle模块提供了四个功能:dumps、dump、loads、load.
import pickle
#存储变量
dic = {'age': 23, 'job': 'student'}
byte_data = pickle.dumps(dic)
print(byte_data)
#out-> b'\x80\x03}q\x00(X\x03\x00\x00\x00jobq\x01X\x07\x00\x00\x00studentq\x02X\x03\x00\x00\x00ageq\x03K\x17u.'
#读取数据
obj=pickle.loads(byte_data)
print(obj)
#out-> {'age': 23, 'job': 'student'}
#也可以存在文件中,使得对象持久化。使用的是dump和load函数,注意和上面的区别,少了s。
#由于pickle写入的是二进制数据,所以打开方式需要以wb和rb的模式。
#序列化
with open('seria_pickle.text','wb') as f:
dic = {'age': 23, 'job': 'student'}
pickle.dump(dic,f)
#反序列化
with open('seria_pickle.text','rb') as f:
data=pickle.load(f)
print(data)
#out-> {'age': 23, 'job': 'student'}
print(type(data))
#out-> <class 'dict'>
序列化用户自定义类对象
class Person:
def __init__(self,name,age,job):
self.name = name
self.age = age
self.job = job
def work(self):
print('%s 正在 %s.' % (self.name,self.job))
# 将实例存储在变量中,当然也能存在文件中
person1 = Person('王思聪',38,'泡妹子')
data1 = pickle.dumps(person1)
print(data1)
#out-> # b'\x80\x03c__main__\nPerson\nq\x00)\x
person2 = pickle.loads(data1)
print(person2)
#out-><__main__.Person object at 0x7f5d6b7f1048>
person2.work()
#out->王思聪 正在 泡妹子.
#将类本身存储在变量中,loads的时候返回类本身,而非它的一个实例
class_Person = pickle.dumps(Person)
Person = pickle.loads(class_Person)
p = Person('马云', 58, '开淘宝')
p.work()
#out->马云 正在 开淘宝.
# 下面这个例子演示的就是将类存储在文件中
#序列化
with open('seria_person.text','wb') as f:
pickle.dump(person1,f)
#person1对象以字节形式存到文件seria_person.text中
#反序列化
with open('seria_person.text','rb') as f:
person_f = pickle.load(f)
print(person_f)
#out-> <__main__.Person object at 0x7f3a83a880b8>
person_f.work()
#out-> 王思聪 正在 泡妹子.
##json模块##
pickle可以很方便地序列化所有对象。不过json作为更为标准的格式,具有更好的可读性(pickle是二进制数据)和跨平台性,跨语言性。是个不错的选择。
json,用于字符串 和 python数据类型间进行转换。
json只能处理简单的数据类型,比如字典,列表等,不支持复杂数据类型,如类等数据类型。
json模块提供了四个功能:dumps、dump、loads、load
import json
class Person:
def __init__(self,name,age,job):
self.name = name
self.age = age
self.job = job
def work(self):
print('%s 正在 %s.' % (self.name,self.job))
person1 = Person('刘强东',40,'泡奶茶')
with open('person_json.text','w',encoding='utf-8') as f:
json.dump(person1, f) # 报错
Object of type ‘Person’ is not JSON serializable此时dump函数里传一个参default就可以了,这个参数接受一个函数,这个函数可以将对象转换为字典。
添加一个函数返回字典
def person2dict(person):
return {'name': person.name,
'age': person.age,
'job': person.job}
person1 = Person('刘强东',40,'泡奶茶')
with open('person_json.text','w',encoding='utf-8') as f:
#这里注意,是以字符串存储,所以用w,再加上编码类型,不能用wb,wb是以二进制存储,
json.dump(person1,f,default=person2dict)
这样返回的就是一个字典了,对象实例有个方法可以简化这一过程。直接调用实例的___dict___。例如
print(person1.__dict__)
{'name': '刘强东', 'age': 40, 'job': '泡奶茶'}
同时在读取的时候load出来的是一个字典,再转回对象就可,同样需要一个object_hook参数,该参数接收一个函数,用于将字典转为对象。
def dict2person(dict):
return Person(dict['name'],dict['age'],dict['job'])
完整函数
import json
class Person:
def __init__(self,name,age,job):
self.name = name
self.age = age
self.job = job
def work(self):
print('%s 正在 %s.' % (self.name,self.job))
def person2dict(person):
return {'name':person.name,
'age':person.age,
'job':person.job
person1 = Person('刘强东',40,'泡奶茶')
with open('person_json.text','w',encoding='utf-8') as f:
#这里注意,是以字符串存储,所以用w,再加上编码类型,不能用wb,wb是以二进制存储,
json.dump(person1,f,default=person2dict)
person1.work()
#out->刘强东 正在 泡奶茶.
def dict2person(dict):
return Person(dict['name'],dict['age'],dict['job'])
with open('person_json.text','r',encoding='utf-8') as f:
person2 = json.load(f,object_hook=dict2person)
print(person2)
#out-><__main__.Person object at 0x7f4813145be0>
person2.work()
#out->刘强东 正在 泡奶茶.
由于可以使用____dict____代替person2dict函数,再使用lambda函数简化。
with open('person_json.text','w',encoding='utf-8') as f:
json.dump(person1,f,default=lambda obj:obj.__dict__)
#使用__dict__和lambda匿名函数简化实例化对象方法
print(person1.__dict__)