9.9 总结
已经介绍了几种用于序列化Python对象的方式。我们可以将类定义编码为多种格式,包括JSON、YAML、Pickle、XML和CSV,每种格式都各有优缺点。
它们对应的类库模块大体上会用于从一个外部文件中加载对象或将对象转储到一个文件中,这些模块的行为并不是完全一致的,但它们是类似的,因此可以使用一些通用的设计模式。
使用CSV和XML格式往往会暴露出比较复杂的设计问题。在Python中的类定义可能会包含对象的引用,而它在CSV或XML格式中并没有一种很好的表达方式。
9.9.1 设计要素和折中方案
Python对象的序列化和持久化的方式有很多。之前介绍的并不是全部。本节中介绍的格式侧重于两个基本的用例。
- 与其他应用进行数据交换:我们需要为其他应用提供或接收数据。对于这类场景,会受限制于其他应用的接口。在应用和框架中,JSON和XML通常是用来进行数据交换的首选格式。在一些情况下,也会考虑使用CSV来交换数据。
- 应用中数据的持久化:对于这类场景,通常使用pickle,因为它已经非常成熟并且是Python标准库中的一部分。然而,YAML格式的可读性是它最主要的一个优势,我们可以查看、编辑并修改。
当使用这些格式时,在设计上需要考虑很多方面。首先,这些格式更倾向于序列化单独的Python对象。它里面可能包含了一个对象的集合,但它仍是一个单独的对象。例如在使用JSON和XML时,在对象序列化之后会附加一个结束分隔符。如果要对一个很大的领域中的每个对象做持久化,可以使用shelve和sqlite3。详细内容可参考第10章“用Shelve保存和获取对象”和第11章“用SQLite保存和获取对象”。
JSON是一种被广泛使用的标准格式。在表示复杂的Python类时,它显得不够方便。当使用JSON时,我们需要考虑到如何使对象与JSON格式兼容。JSON文档的可读性很强,JSON自身的限制使得它在互联网传输的过程中是安全的。
YAML并不像JSON这样常用,但是它为序列化与持久化的过程提供了很多方便。YAML文档可读性很强,对于可编辑的配置文件来说,YAML是理想的。我们可使用安全加载选项来确保YAML使用过程中的安全性。
Pickle对于简单、轻量级对象的持久化是理想选择。在从Python到Python的传输中,它算是一种比较紧凑的格式。CSV是一种被广泛使用的标准。而使用CSV格式来表达Python对象并不是一件容易的事情。当在CSV格式中共享数据时,通常在应用程序中以namedtuples为结尾,并且必须提供在Python与CSV之间映射的实现。
XML是另一种在序列化中被广泛使用的格式。XML非常灵活,因此有很多方式可以将Python对象转换为XML。对于XML用例,通常使用XSD或DTD来对外部规格进行说明。解析XML并创建Python对象的处理过程通常很复杂。
由于每个CSV的行在很大程度上是相互独立的,因此我们可以对CSV中的很多对象构成的集合批量地进行编码和解码。从这点来看,对于无法一次性加载入内存的大集合来说,使用CSV进行编码和解码是很方便的。
有些情况下,我们会遇到混合设计的问题。当从格式比较新的电子表格中读取数据时,会遇到嵌套在XML格式中的CSV的行和列的解析问题。例如,OpenOffice.rog.ODS文件压缩的档案。归档中的一个文件是content.xml文件。对body/spreadsheet/table元素使用XPath搜索将会分别根据表格文件中的每个标签进行查找。在每个表中,会发现table-row元素(通常)与Python对象之间是对应的。在每行中,可以看到table-cell元素中包含了用于创建对象属性的值。
9.9.2 模式演化
在对象持久化的过程中,必须先解决模式演化的问题。对象中包含了动态的状态和静态的类定义,可以容易地对动态的状态进行持久化,而类定义则为持久化数据的模型。然而,类并不是完全静态的。需要有一种规定,用于定义当类发生变化时,如何加载上一版本所保存的数据。
在对主次版本号进行区分时,最好考虑到与外部文件的兼容性。主版本意味着文件不再兼容,必须进行转换。次版本意味着文件格式是兼容的并且在升级过程并不涉及任何数据转换。
一种常见的做法是,将主版本号包含在文件扩展名中。我们可能会有文件名以.json2或.json3为结尾用于标识所使用的数据格式。要同时支持持久化文件的多个版本是很困难的。为了版本升级的过程更流畅,应用应该能够对之前的文件格式进行解码。通常情况下,最好使用最新的、数字最大的文件格式来做持久化,尽管其他格式也是可以使用的。
在接下来的几章中,会研究多对象的序列化过程。在shelve和sqlite3模块中,提供了多种方式同时序列化大批不同的对象。之后,会使用这些技术以及表述性状态传递(REST)来完成进程间对象的传输。而且,还会继续使用这些技术处理配置文件。
9.9.3 展望
在第10章“用Shelve保存和获取对象”和第11章“用SQLite保存和获取对象”中,将会介绍两种常用的方式,用于包含很多对象的大集合对象的持久化。在这两章中,分别介绍了不同的用来创建Python对象的数据库的方式。
在第12章“传输和共享对象”中,将使用这些序列化技术使得对象可以在另一个进程中可用。并将主要使用RESTful的Web服务完成对象在进程间的传输,因为它简单而且普遍。
在第13章“配置文件和持久化”中,我们会再次使用这些序列化技术。在这种情形下,会使用JSON或YAML格式来对应用中的配置文件进行编码。
