9.9 永久存储模块
在本书的很多练习里,都需要用户输入数据。这可能需要用户多次输入重复的数据,尤其是如果你要输入大批数据供以后使用时,你肯定会厌烦。这就是永久储存大显身手的地方了,它可以把用户的数据归档保存起来供以后使用,这样你就可以避免每次输入同样的信息。在简单的磁盘文件已经不能满足你的需要,而使用完整的关系数据库管理系统(relational database management systems,RDBMS)又有些大材小用时,简单的永久性储存就可以发挥它的作用。大部分永久性储存模块是用来储存字符串数据的,但是也有方法来归档Python对象。
9.9.1 pickle和 marshal模块
Python提供了许多可以实现最小化永久性储存的模块。其中的一组(marshal和pickle)可以用来转换并储存Python对象。该过程将比基本类型复杂的对象转换为一个二进制数据集合,这样就可以把数据集合保存起来或通过网络发送,然后再重新把数据集合恢复原来的对象格式。这个过程也被称为数据的扁平化、数据的序列化或者数据的顺序化。另外一些模块(dbhash/bsddb,dbm,gdbm,dumbdbm等)及它们的“管理器” (anydbm)只提供了 Python字符串的永久性储存。而最后一个模块(shelve)则两种功能都具备。
我们已经提到marshal和pickle模块都可以对Python对象进行储存转换。这些模块本身并没有提供“永久性储存”的功能,因为它们没有为对象提供名称空间,也没有提供对永久性储存对象的并发写入访问(concuirent write access)o它们只能储存转换Python对象,为保存和传输提供方便。数据储存是有次序的(对象的储存和传输是一个接一个进行的)。marshal和pickle模块的区别在于marshal只能处理简单的Python对象(数字、序列、映射以及代码对象),而pickle还可以处理递归对象,被不同地方多次引用的对象,以及用户定义的类和实例。pickle模块还有一个增强的版本叫cPickle,使用C实现了相关的功能。
9.9.2 DBM风格的模块
db系列的模块使用传统的DBM格式写入数据,Python提供了 DBM的多种实现:dbhash/bsddb、dbm、gdbm和dumbdbm等。你可以随便按照你的爱好使用,如果你不确定的话,那么最好使用anydbm模块,它会自动检测系统上已安装的DBM兼容模块,并选择“最好”的一个。 dumbdbm模块是功能最少的一个,在没有其他模块可用时,anydbm才会选择。这些模块为用户的对象提供了一个命名空间,这些对象同时具备字典对象和文件对象的特点。不过不足之处在于它们只能储存字符串,不能对Python对象进行序列化。
9.9.3 shelve模块
最后,我们来看一个更为完整的解决方案,shelve模块。shelve模块使用anydbm模块寻找合适的DBM模块,然后使用cPickle来完成对储存转换过程。shelve模块允许对数据库文件进行并发的读访问,但不允许共享读/写访问。这也许是我们在Python标准库里找到的最接近于永久性储存的东西了。可能有一些第三方模块实现了“真正”的永久性储存。图9-1展示了储存转换模块与永久性储存模块之间的关系,以及为何shelve对象能成为两者的最好的选择的。
图 9-1 用于序列化和永久性储存的 Python模块
核心模块: pickle和 cPickle
你可以使用pickle模块把Python对象直接保存到文件里,而不需要把它们转化为字符串,也不用底层的文件访问操作把它们写入到一个二进制文件里。pickle模块会创建一个Python语言专用的二进制格式,你不需要考虑任何文件细节,它会帮你干净利索地完成读写对象操作,唯一需要的只是一个合法的文件句柄。
pickle模块中的两个主要函数是dump()和load()。dump()函数接受一个文件句柄和一个数据对象作为参数,把数据对象以特定格式保存到给定文件里。当我们使用load()函数从文件中取出已保存的对象时,pickle知道如何恢复这些对象到它们本来的格式。我们建议你看一看pickle和更“聪明”的shelve模块,后者提供了字典式的文件对象访问功能,进一步减少了程序员的工作。
cPickle是pickle的一个更快的C语言编译版本。