持久性就是指保持对象,甚至在多次执行同一程序之间也保持对象。通过本文,您会对Python对象的各种持久性机制(从关系数据库到Python的pickle以及其它机制)有一个总体认识。另外,还会让您更深一步地了解Python的对象序列化能力。
什么是持久性?
持久性的基本思想很简单。假定有一个Python程序,它可能是一个管理日常待办事项的程序,您希望在多次执行这个程序之间可以保存应用程序对象(待办事项)。换句话说,您希望将对象存储在磁盘上,便于以后检索。这就是持久性。要达到这个目的,有几种方法,每一种方法都有其优缺点。
例如,可以将对象数据存储在某种格式的文本文件中,譬如CSV文件。或者可以用关系数据库,譬如Gadfly、MySQL、PostgreSQL或者DB2。这些文件格式和数据库都非常优秀,对于所有这些存储机制,Python都有健壮的接口。
这些存储机制都有一个共同点:存储的数据是独立于对这些数据进行操作的对象和程序。这样做的好处是,数据可以作为共享的资源,供其它应用程序使用。缺点是,用这种方式,可以允许其它程序访问对象的数据,这违背了面向对象的封装性原则—即对象的数据只能通过这个对象自身的公共(public)接口来访问。
另外,对于某些应用程序,关系数据库方法可能不是很理想。尤其是,关系数据库不理解对象。相反,关系数据库会强行使用自己的类型系统和关系数据模型(表),每张表包含一组元组(行),每行包含具有固定数目的静态类型字段(列)。如果应用程序的对象模型不能够方便地转换到关系模型,那么在将对象映射到元组以及将元组映射回对象方面,会碰到一定难度。这种困难常被称为阻碍性不匹配(impedence-mismatch)问题。
对象持久性
如果希望透明地存储Python对象,而不丢失其身份和类型等信息,则需要某种形式的对象序列化:它是一个将任意复杂的对象转成对象的文本或二进制表示的过程。同样,必须能够将对象经过序列化后的形式恢复到原有的对象。在Python中,这种序列化过程称为pickle,可以将对象pickle成字符串、磁盘上的文件或者任何类似于文件的对象,也可以将这些字符串、文件或任何类似于文件的对象unpickle成原来的对象。我们将在本文后面详细讨论pickle。
假定您喜欢将任何事物都保存成对象,而且希望避免将对象转换成某种基于非对象存储的开销;那么pickle文件可以提供这些好处,但有时可能需要比这种简单的pickle文件更健壮以及更具有可伸缩性的事物。例如,只用pickle不能解决命名和查找pickle文件这样的问题,另外,它也不能支持并发地访问持久性对象。如果需要这些方面的功能,则要求助类似于ZODB(针对Python的Z对象数据库)这类数据库。ZODB是一个健壮的、多用户的和面向对象的数据库系统,它能够存储和管理任意复杂的Python对象,并支持事务操作和并发控制。(请参阅参考资料,以下载ZODB。)令人足够感兴趣的是,甚至ZODB也依靠Python的本机序列化能力,而且要有效地使用ZODB,必须充分了解pickle。
另一种令人感兴趣的解决持久性问题的方法是Prevayler,它最初是用Java实现的(有关Prevaylor方面的developerWorks文章,请参阅参考资料)。最近,一群Python程序员将Prevayler移植到了Python上,另起名为PyPerSyst,由SourceForge托管(有关至PyPerSyst项目的链接,请参阅参考资料)。Prevayler/PyPerSyst概念也是建立在Java和Python语言的本机序列化能力之上。PyPerSyst将整个对象系统保存在内存中,并通过不时地将系统快照pickle到磁盘以及维护一个命令日志(通过此日志可以重新应用最新的快照)来提供灾难恢复。所以,尽管使用PyPerSyst的应用程序受到可用内存的限制,但好处是本机对象系统可以完全装入到内存中,因而速度极快,而且实现起来要比如ZODB这样的数据库简单,ZODB允许对象的数目比同时在能内存中所保持的对象要多。
既然我们已经简要讨论了存储持久对象的各种方法,那么现在该详细探讨pickle过程了。虽然我们主要感兴趣的是探索以各种方式来保存Python对象,而不必将其转换成某种其它格式,但我们仍然还有一些需要关注的地方,譬如:如何有效地pickle和unpickle简单对象以及复杂对象,包括定制类的实例;如何维护对象的引用,包括循环引用和递归引用;以及如何处理类定义发生的变化,从而使用以前经过pickle的实例时不会发生问题。我们将在随后关于Python的pickle能力探讨中涉及所有这些问题。
一些经过pickle的Python
pickle模块及其同类模块cPickle向Python提供了pickle支持。后者是用C编码的,它具有更好的性能,对于大多数应用程序,推荐使用该模块。我们将继续讨论pickle,但本文的示例实际是利用了cPickle。由于其中大多数示例要用Pythonshell来显示,所以先展示一下如何导入cPickle,并可以作为pickle来引用它:
>>>importcPickleaspickle
现在已经导入了该模块,接下来让我们看一下pickle接口。pickle模块提供了以下函数对:dumps(object)返回一个字符串,它包含一个pickle格式的对象;loads(string)返回包含在pickle字符串中的对象;dump(object,file)将对象写到文件,这个文件可以是实际的物理文件,但也可以是任何类似于文件的对象,这个对象具有write()方法,可以接受单个的字符串参数;load(file)返回包含在pickle文件中的对象。
缺省情况下,dumps()和dump()使用可打印的ASCII表示来创建pickle。两者都有一个final参数(可选),如果为True,则该参数指定用更快以及更小的二进制表示来创建pickle。loads()和load()函数自动检测pickle是二进制格式还是文本格式。
以上内容为大家介绍了pythonpickle模块,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注IT培训机构:千锋教育。