16.1 serialization
marshal
通常不建议用来存储自定义数据。
支持:None, bool, int, long, float, complex, str, unicode, tuple, list, set, frozenset, dict,
code objects, StopIteration。容器元素必须是所支持类型,不能是递归引用
>>> s = dumps((1, 2, 3))
>>> s
b'\xa9\x03\xe9\x01\x00\x00\x00\xe9\x02\x00\x00\x00\xe9\x03\x00\x00\x00'
>>> loads(s)
(1, 2, 3)
>>>
>>> with open('test.dat', 'wb') as f:
... dump((1, 2, 3), f)
...
17
>>> with open('test.dat', 'rb') as f:
... print(load(f))
...
(1, 2, 3)
>>>
>>> help(dump)
pickle
支持用户自定义类型,支持三种协议版本:
• 0: 使用可显示的 ASCII 字符编码,便于阅读和手工编辑。(默认)
• 1: 兼容早期 Python 版本的二进制格式。
• 2: 最有效的二进制编码格式
>>> import pickle
>>> s = 'hello, world'
>>> d = pickle.dumps(s)
>>>
>>> d
b'\x80\x03X\x0c\x00\x00\x00hello, worldq\x00.'
>>> pickle.loads(d)
'hello, world'
同样有读写文件的 dump、load 函数。看看支持的数据类型:
• None, True, False
• int, long, float, complex
• str, unicode
• tuple, list, set, and dict (元素必须是支持类型)
• function (模块级别的函数)
• classe (模块级别的自定义类,非嵌套)
• instance (有 __dict__ 属性,或者实现 pickle protocol 协议)
>>> class Data(object):
... def __init__(self, x,y):
... print('__init__')
... self._x = x
... self._y = y
...
>>>
>>> d = Data(100, 200)
__init__
>>> s = pickle.dumps(d, 2)
>>> s
b'\x80\x02c__main__\nData\nq\x00)\x81q\x01}q\x02(X\x02\x00\x00\x00_xq\x03KdX\x02\x00\x00\x00_yq\x04K\xc8ub.'
>>> d2 = pickle.loads(s)
>>> d2.__dict__
{'_x': 100, '_y': 200}
利用 pickle protocol 可以控制序列化的细节。比如不保留_y字段
import pickle class Data(object): def __init__(self, x, y): self._x = x self._y = y def __getstate__(self): d = self.__dict__.copy() print('__getstate__') del d['_y'] return d def __setstate__(self, state): print('__setstate__: ', state) self.__dict__.update(state) d = Data(10, 20) s = pickle.dumps(d, 2) # __getstate__ d2 = pickle.loads(s) # __setstate__: {'_x': 10} print(d2.__dict__) # {'_x': 10}
在使用pickle序列化时,Pickle 每次序列化生成的字符串有独立头尾,pickle.load() 只会读取一个完整的结果。如果多次pickle.dump,则需要多次dump.load才能读取完成。
if __name__ == '__main__': f = open('data', 'wb') pickle.dump([1, 2, 3], f) pickle.dump('hello', f) pickle.dump({'hi': 'haha'}, f) f.close() with open('data', 'rb') as f: try: while True: print(pickle.load(f)) except EOFError: print('加载完毕')