专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »Linux » 对象序列化:LINUX应用技巧,序列化存储 Python 对象 »正文

对象序列化:LINUX应用技巧,序列化存储 Python 对象

来源: 发布时间:星期四, 2008年12月4日 浏览:20次 评论:0

  什么是持久性?
  持久性的基本思想很简单。假定有一个 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,它最初是用 实现的(有关 Prevaylor 方面的 developerWorks 文章,请参阅参考资料)。最近,一群 Python 程序员将 Prevayler 移植到了 Python 上,另起名为 PyPerSyst,由 SourceForge 托管(有关至 PyPerSyst 项目的链接,请参阅参考资料)。Prevayler/PyPerSyst 概念也是建立在 和 Python 语言的本机序列化能力之上。PyPerSyst 将整个对象系统保存在内存中,并通过不时地将系统快照 pickle 到磁盘以及维护一个命令日志(通过此日志可以重新应用最新的快照)来提供灾难恢复。所以,尽管使用 PyPerSyst 的应用程序受到可用内存的限制,但好处是本机对象系统可以完全装入到内存中,因而速度极快,而且实现起来要比如 ZODB 这样的数据库简单,ZODB 允许对象的数目比同时在能内存中所保持的对象要多。
  
  既然我们已经简要讨论了存储持久对象的各种方法,那么现在该详细探讨 pickle 过程了。虽然我们主要感兴趣的是探索以各种方式来保存 Python 对象,而不必将其转换成某种其它格式,但我们仍然还有一些需要关注的地方,譬如:如何有效地 pickle 和 unpickle 简单对象以及复杂对象,包括定制类的实例;如何维护对象的引用,包括循环引用和递归引用;以及如何处理类定义发生的变化,从而使用以前经过 pickle 的实例时不会发生问题。我们将在随后关于 Python 的 pickle 能力探讨中涉及所有这些问题。
  
  一些经过 pickle 的 Python
  pickle 模块及其同类模块 cPickle 向 Python 提供了 pickle 支持。后者是用 C 编码的,它具有更好的性能,对于大多数应用程序,推荐使用该模块。我们将继续讨论 pickle,但本文的示例实际是利用了 cPickle。由于其中大多数示例要用 Python shell 来显示,所以先展示一下如何导入 cPickle,并可以作为 pickle 来引用它:
  
  >>> import cPickle as pickle
  现在已经导入了该模块,接下来让我们看一下 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 是二进制格式还是文本格式。
  
  清单 1 显示了一个交互式会话,这里使用了刚才所描述的 dumps() 和 loads() 函数:
  
  清单 1. dumps() 和 loads() 的演示
  Welcome To PyCrust 0.7.2 - The Flakiest Python Shell
  Sponsored by Orbtech - Your source for Python programming expertise.
  Python 2.2.1 (#1, Aug 27 2002, 10:22:32)
  [GCC 3.2 (Mandrake Linux 9.0 3.2-1mdk)] _disibledevent= pickle.load(f2)
  >>> c2
  ['fee', 'fie', 'foe', 'fum']
  >>> f2.close()
  
  Pickle 的威力
  到目前为止,我们讲述了关于 pickle 方面的基本知识。在这一节,将讨论一些高级问题,当您开始 pickle 复杂对象时,会遇到这些问题,其中包括定制类的实例。幸运的是,Python 可以很容易地处理这种情形。
  
  可移植性
  从空间和时间上说,Pickle 是可移植的。换句话说,pickle 文件格式独立于机器的体系结构,这意味着,例如,可以在 Linux 下创建一个 pickle,然后将它发送到在 或 Mac OS 下运行的 Python 程序。并且,当升级到更新版本的 Python 时,不必担心可能要废弃已有的 pickle。Python 开发人员已经保证 pickle 格式将可以向后兼容 Python 各个版本。事实上,在 pickle 模块中提供了有关目前以及所支持的格式方面的详细信息:
  
  清单 3. 检索所支持的格式
  >>> pickle.format_version
  '1.3'
  >>> pickle.compatible_formats
  ['1.0', '1.1', '1.2']
  
  多个引用,同一对象
  在 Python 中,变量是对象的引用。同时,也可以用多个变量引用同一个对象。经证明,Python 在用经过 pickle 的对象维护这种行为方面丝毫没有困难,如清单 4 所示:

相关文章

读者评论

  • 共0条 分0页

发表评论

  • 昵称:
  • 内容: