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


接下来,我们看一些示例,这些示例用到了 dump() 和 load(),它们使用文件和类似文件的对象。这些函数的操作非常类似于我们刚才所看到的 dumps() 和 loads(),区别在于它们还有另一种能力 — dump() 函数能一个接着一个地将几个对象转储到同一个文件。随后调用 load() 来以同样的顺序检索这些对象。清单 2 显示了这种能力的实际应用:

清单 2. dump() 和 load() 示例

>>> a1 = 'apple'

>>> b1 = {1: 'One', 2: 'Two', 3: 'Three'}

>>> c1 = ['fee', 'fie', 'foe', 'fum']

>>> f1 = file('temp.pkl', 'wb')

>>> pickle.dump(a1, f1, True)

>>> pickle.dump(b1, f1, True)

>>> pickle.dump(c1, f1, True)

>>> f1.close()

>>> f2 = file('temp.pkl', 'rb')

>>> a2 = pickle.load(f2)

>>> a2

'apple'

>>> b2 = pickle.load(f2)

>>> b2

{1: 'One', 2: 'Two', 3: 'Three'}

>>> c2 = pickle.load(f2)

>>> c2

['fee', 'fie', 'foe', 'fum']

>>> f2.close()

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

共4页 首页 上一页 [1] [2] [3] [4下一页 尾页>
字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z