序列化(Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。 在序列化期间,对象将其当前状态写入到临时或持久性存储区。 以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。 序列化使其他代码可以查看或修改,那些不序列化便无法访问的对象实例数据。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
大多数情况就是指将对象从内存保存到硬盘
在python中使用pickle模块来实现序列化及反序列化
序列化:
pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件。
pickle.dump()直接把对象序列化后写入一个file-like Object。
>>> li = ["cael", 123] >>> pickle.dump(li) >>> pickle.dumps(li) b'\x80\x03]q\x00(X\x04\x00\x00\x00caelq\x01K{e.' |
>>> f= open('a.dat', 'wb') >>> d = {'name': 'carl', 'age': 20} >>> import pickle >>> pickle.dump(d, f) >>> f.close() |
反序列化:就是将已经序列化的数据重新3变为对象
可以先把内容读到一个bytes,然后用pickle.loads()方法反序列化出对象
也可以直接用pickle.load()方法从一个file-like Object中直接反序列化出对象
>>> f = open('a.dat', 'rb') >>> b = f.read() >>> b b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x04\x00\x00\x00carlq\x02X\x03\x00\x00\x00ageq\x03K\x14u.' >>> pickle.loads(b) {'name': 'carl', 'age': 20} >>> f.close() |
>>> f = open('a.dat', 'rb') >>> d = pickle.load(f) >>> d {'name': 'carl', 'age': 20} >>> f.close() |
内置对象与JSON的相互转化
所需模块: json
内置对象转化为json可以使用json.dumps()方法,该方法返回一个字符串,也可以使用json.dump()方法,直接将对象写入一个file-like Object
>>> import json >>> d= {'name': 'bill', 'age': 12} >>> js = json.dumps(d) >>> js '{"name": "bill", "age": 12}' >>> f = open('a.dat', 'w') >>> json.dump(d, f) >>> f.close() |
从file-like Object中读出json数据并转化成内置对象
>>> f = open('a.dat', 'r') >>> js = f.read() >>> d = json.loads(js) >>> d {'name': 'bill', 'age': 12} >>> d2 = json.load(f) Traceback (most recent call last): File "<pyshell#50>", line 1, in <module> d2 = json.load(f) File "D:\python36\lib\json\__init__.py", line 299, in load parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw) File "D:\python36\lib\json\__init__.py", line 354, in loads return _default_decoder.decode(s) File "D:\python36\lib\json\decoder.py", line 339, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "D:\python36\lib\json\decoder.py", line 357, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) >>> f.close() >>> f = open('a.dat', 'r') >>> d2 = json.load(f) >>> d2 {'name': 'bill', 'age': 12} |
在使用完loads()方法后再使用load()方法时出现了错误,原因在于 f 的文件指针在执行完loads()方法后已经指向了文件末尾。需要重新打开文件或者将文件指针移到文件开头才行。
将任意类转化为json
原理:先将实例的属性转化为dict,再调用json.load()/json.loads()将dict序列化
-
import json
-
-
class Stu(object):
-
def __init__(self, name, age):
-
self._name = name
-
self._age = age
-
-
s = Stu('alice', 11)
-
js = json.dumps(s, default = lambda obj : obj.__dict__)
>>> js '{"_name": "alice", "_age": 11}' |
这里第9行写的匿名函数的原理:
因为通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。也有少数例外,比如定义了__slots__的class。(廖雪峰)
所以其实可以自己写一个转换函数作为default参数,但是我们考虑到如果要为每种需要序列化的类写一个这种函数,显然没有这样写划算。
将json转化为类,这里就要针对不同的要转化的类写一个相应函数,其实也就是将json数据作为参数再创建一个实例
-
import json
-
-
class Stu(object):
-
def __init__(self, name, age):
-
self._name = name
-
self._age = age
-
-
s = Stu('alice', 11)
-
js = json.dumps(s, default = lambda obj : obj.__dict__)
-
-
# 如果要转化的类的初始化方法的参数是可变参数或关键字参数的话
-
# 可以写出通用性更高的转换函数,因为可以直接将json组装成 tuple 或 dict
-
def json2Stu(js):
-
return Stu(js["_name"], js["_age"] )
-
-
s2 = json.loads(js, object_hook = json2Stu)
>>> js '{"_name": "alice", "_age": 11}' >>> s2 <__main__.Stu object at 0x000001B737BF75F8> >>> s2._name 'alice' |