中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > 综合其它
LINUX应用技巧,序列化存储 Python 对象(2)
作者:佚名 时间:2007-09-18 16:33 出处:ibm 责编:月夜寒箫
              摘要:LINUX应用技巧,序列化存储 Python 对象(2)
Pickle 的威力

 

到目前为止,我们讲述了关于 pickle 方面的基本知识。在这一节,将讨论一些高级问题,当您开始 pickle 复杂对象时,会遇到这些问题,其中包括定制类的实例。幸运的是,Python 可以很容易地处理这种情形。

可移植性

从空间和时间上说,Pickle 是可移植的。换句话说,pickle 文件格式独立于机器的体系结构,这意味着,例如,可以在 Linux 下创建一个 pickle,然后将它发送到在 Windows 或 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 所示:

清单 4. 对象引用的维护

>>> a = [1, 2, 3]

>>> b = a

>>> a

[1, 2, 3]

>>> b

[1, 2, 3]

>>> a.append(4)

>>> a

[1, 2, 3, 4]

>>> b

[1, 2, 3, 4]

>>> c = pickle.dumps((a, b))

>>> d, e = pickle.loads(c)

>>> d

[1, 2, 3, 4]

>>> e

[1, 2, 3, 4]

>>> d.append(5)

>>> d

[1, 2, 3, 4, 5]

>>> e

[1, 2, 3, 4, 5]

循环引用和递归引用

可以将刚才演示过的对象引用支持扩展到循环引用(两个对象各自包含对对方的引用)和递归引用(一个对象包含对其自身的引用)。下面两个清单着重显示这种能力。我们先看一下递归引用:

清单 5. 递归引用

>>> l = [1, 2, 3]

>>> l.append(l)

>>> l

[1, 2, 3, [...]]

>>> l[3]

[1, 2, 3, [...]]

>>> l[3][3]

[1, 2, 3, [...]]

>>> p = pickle.dumps(l)

>>> l2 = pickle.loads(p)

>>> l2

[1, 2, 3, [...]]

>>> l2[3]

[1, 2, 3, [...]]

>>> l2[3][3]

[1, 2, 3, [...]]

现在,看一个循环引用的示例:

清单 6. 循环引用

>>> a = [1, 2]

>>> b = [3, 4]

>>> a.append(b)

>>> a

[1, 2, [3, 4]]

>>> b.append(a)

>>> a

[1, 2, [3, 4, [...]]]

>>> b

[3, 4, [1, 2, [...]]]

>>> a[2]

[3, 4, [1, 2, [...]]]

>>> b[2]

[1, 2, [3, 4, [...]]]

>>> a[2] is b

1

>>> b[2] is a

1

>>> f = file('temp.pkl', 'w')

>>> pickle.dump((a, b), f)

>>> f.close()

>>> f = file('temp.pkl', 'r')

>>> c, d = pickle.load(f)

>>> f.close()

>>> c

[1, 2, [3, 4, [...]]]

>>> d

[3, 4, [1, 2, [...]]]

>>> c[2]

[3, 4, [1, 2, [...]]]

>>> d[2]

[1, 2, [3, 4, [...]]]

>>> c[2] is d

1

>>> d[2] is c

1

注意,如果分别 pickle 每个对象,而不是在一个元组中一起 pickle 所有对象,会得到略微不同(但很重要)的结果,如清单 7 所示:

清单 7. 分别 pickle vs. 在一个元组中一起 pickle

>>> f = file('temp.pkl', 'w')

>>> pickle.dump(a, f)

>>> pickle.dump(b, f)

>>> f.close()

>>> f = file('temp.pkl', 'r')

>>> c = pickle.load(f)

>>> d = pickle.load(f)

>>> f.close()

>>> c

[1, 2, [3, 4, [...]]]

>>> d

[3, 4, [1, 2, [...]]]

>>> c[2]

[3, 4, [1, 2, [...]]]

>>> d[2]

[1, 2, [3, 4, [...]]]

>>> c[2] is d

0

>>> d[2] is c

0

相等,但并不总是相同

正如在上一个示例所暗示的,只有在这些对象引用内存中同一个对象时,它们才是相同的。在 pickle 情形中,每个对象被恢复到一个与原来对象相等的对象,但不是同一个对象。换句话说,每个 pickle 都是原来对象的一个副本:

清单 8. 作为原来对象副本的被恢复的对象

>>> j = [1, 2, 3]

>>> k = j

>>> k is j

1

>>> x = pickle.dumps(k)

>>> y = pickle.loads(x)

>>> y

[1, 2, 3]

>>> y == k

1

>>> y is k

0

>>> y is j

0

>>> k is j

1

同时,我们看到 Python 能够维护对象之间的引用,这些对象是作为一个单元进行 pickle 的。然而,我们还看到分别调用 dump() 会使 Python 无法维护对在该单元外部进行 pickle 的对象的引用。相反,Python 复制了被引用对象,并将副本和被 pickle 的对象存储在一起。对于 pickle 和恢复单个对象层次结构的应用程序,这是没有问题的。但要意识到还有其它情形。

值得指出的是,有一个选项确实允许分别 pickle 对象,并维护相互之间的引用,只要这些对象都是 pickle 到同一文件即可。pickle 和 cPickle 模块提供了一个 Pickler(与此相对应是 Unpickler),它能够跟踪已经被 pickle 的对象。通过使用这个 Pickler,将会通过引用而不是通过值来 pickle 共享和循环引用:

清单 9. 维护分别 pickle 的对象间的引用

>>> f = file('temp.pkl', 'w')

>>> pickler = pickle.Pickler(f)

>>> pickler.dump(a)



>>> pickler.dump(b)



>>> f.close()

>>> f = file('temp.pkl', 'r')

>>> unpickler = pickle.Unpickler(f)

>>> c = unpickler.load()

>>> d = unpickler.load()

>>> c[2]

[3, 4, [1, 2, [...]]]

>>> d[2]

[1, 2, [3, 4, [...]]]

>>> c[2] is d

1

>>> d[2] is c

1

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有