数据存储
serialization
marshal
Python 专用的序列化算法,PyCodeObject 就是用该算法序列化后保存到 pyc 二进制文件。与具体的机器架构无关,但可能随 Python 版本发生变化。通常不建议用来存储自定义数据。
支持:None, bool, int, long, float, complex, str, unicode, tuple, list, set, frozenset, dict,code objects, StopIteration。容器元素必须是所支持类型,不能是递归引用。
>>> from marshal import dump, load, dumps, loads
>>> s = dumps(range(10))
>>> s
'[\n\x00\x00\x00i\x00\...\x00\x00'
>>> loads(s)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
保存序列化结果到文件。
>>> with file("test.dat", "w") as f:
... dump(range(10), f)
>>> with file("test.dat", "r") as f:
... print load(f)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
pickle
应该用 cPickle 代替 pickle,按官方文档的说法有千倍的提升,且可相互替换。支持用户自定义类型,支持三种协议版本:
- 0: 使用可显示的 ASCII 字符编码,便于阅读和手工编辑。(默认)
- 1: 兼容早期 Python 版本的二进制格式。
- 2: 最有效的二进制编码格式。
>>> import pickle, cPickle
>>> s = "Hello, World"
>>> d = cPickle.dumps(s, 2)
>>> d
'\x80\x02U\rHello, Worldq\x01.'
>>> cPickle.loads(d)
'Hello, World'
>>> pickle.loads(d) # 和 pickle 格式完全相同。
'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 = cPickle.dumps(d, 2)
>>> d2 = cPickle.loads(s) # 反序列化并没有调用 __init__
>>> d2.__dict__
{'_x': 100, '_y': 200}
利用 pickle protocol 可以控制序列化的细节。比如下面例子中,我们不像保留 _y 字段。
>>> class Data(object):
... def __init__(self, x, y):
... self._x = x
... self._y = y
...
... def __getstate__(self):
... d = self.__dict__.copy()
... del d["_y"]
... return d
...
... def __setstate__(self, state):
... self.__dict__.update(state)
>>> d = Data(10, 20)
>>> s = cPickle.dumps(d, 2)
>>> d2 = cPickle.loads(s)
>>> d2.__dict__
{'_x': 10}
shevle
将对象 pickle 序列化,然后保存到 anydbm 格式文件。anydbm 是个 KV 结构的数据库,可以保存多个序列化的对象。当然也可以选择使用 dbm、gdbm、bdb。
- flag: r 读, w 写, c 读写, n 新建、读写。
- protocol: pickle 版本。
- writeback: 允许将变更的对象同步到数据库。(还是显式修改保存比较好)
>>> import shelve
>>> from contextlib import closing
>>> with closing(shelve.open("test", protocol = 2)) as f:
... f["a"] = dict(name = "Tom", age = 34, sex = "male")
... f["b"] = (1, ["a", 3], "abcdefg")
>>> !xxd -g 1 -l 100 test.db
0000000: 00 06 15 61 00 00 00 02 00 00 04 d2 00 00 10 00 ...a............
0000010: 00 00 00 0c 00 00 01 00 00 00 01 00 00 00 00 08 ................
0000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000060: 00 00 00 00 ....
>>> with closing(shelve.open("test", protocol = 2)) as f:
... print f["a"]
... print f["b"]
... print ["c"]
{'age': 34, 'name': 'Tom', 'sex': 'male'}
(1, ['a', 3], 'abcdefg')
['c']