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

[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

不可 pickle 的对象 特殊的状态方法

一些对象类型是不可 pickle 的。例如,Python 不能 pickle 文件对象(或者任何带有对文件对象引用的对象),因为 Python 在 unpickle 时不能保证它可以重建该文件的状态(另一个示例比较难懂,在这类文章中不值得提出来)。试图 pickle 文件对象会导致以下错误:

清单 10. 试图 pickle 文件对象的结果

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

>>> p = pickle.dumps(f)

Traceback (most recent call last):

File "", line 1, in ?

File "/usr/lib/python2.2/copy_reg.py", line 57, in _reduce

raise TypeError, "can't pickle %s objects" % base.__name__

TypeError: can't pickle file objects

类实例

与 pickle 简单对象类型相比,pickle 类实例要多加留意。这主要由于 Python 会 pickle 实例数据(通常是 _dict_ 属性)和类的名称,而不会 pickle 类的代码。当 Python unpickle 类的实例时,它会试图使用在 pickle 该实例时的确切的类名称和模块名称(包括任何包的路径前缀)导入包含该类定义的模块。另外要注意,类定义必须出现在模块的最顶层,这意味着它们不能是嵌套的类(在其它类或函数中定义的类)。

当 unpickle 类的实例时,通常不会再调用它们的 _init_() 方法。相反,Python 创建一个通用类实例,并应用已进行过 pickle 的实例属性,同时设置该实例的 _class_ 属性,使其指向原来的类。

对 Python 2.2 中引入的新型类进行 unpickle 的机制与原来的略有不同。虽然处理的结果实际上与对旧型类处理的结果相同,但 Python 使用 copy_reg 模块的 _reconstructor() 函数来恢复新型类的实例。

如果希望对新型或旧型类的实例修改缺省的 pickle 行为,则可以定义特殊的类的方法 _getstate_() 和 _setstate_(),在保存和恢复类实例的状态信息期间,Python 会调用这些方法。在以下几节中,我们会看到一些示例利用了这些特殊的方法。

现在,我们看一个简单的类实例。首先,创建一个 persist.py 的 Python 模块,它包含以下新型类的定义:

清单 11. 新型类的定义

class Foo(object):

def __init__(self, value):

self.value = value

现在可以 pickle Foo 实例,并看一下它的表示:

清单 12. pickle Foo 实例

>>> import cPickle as pickle

>>> from Orbtech.examples.persist import Foo

>>> foo = Foo('What is a Foo?')

>>> p = pickle.dumps(foo)

>>> print p

ccopy_reg

_reconstructor

p1

(cOrbtech.examples.persist

Foo

p2

c__builtin__

object

p3

NtRp4

(dp5

S'value'

p6

S'What is a Foo?'

sb.

>>>

可以看到这个类的名称 Foo 和全限定的模块名称 Orbtech.examples.persist 都存储在 pickle 中。如果将这个实例 pickle 成一个文件,稍后再 unpickle 它或在另一台机器上 unpickle,则 Python 会试图导入 Orbtech.examples.persist 模块,如果不能导入,则会抛出异常。如果重命名该类和该模块或者将该模块移到另一个目录,则也会发生类似的错误。

这里有一个 Python 发出错误消息的示例,当我们重命名 Foo 类,然后试图装入先前进行过 pickle 的 Foo 实例时会发生该错误:

清单 13. 试图装入一个被重命名的 Foo 类的经过 pickle 的实例

>>> import cPickle as pickle

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

>>> foo = pickle.load(f)

Traceback (most recent call last):

File "", line 1, in ?

AttributeError: 'module' object has no attribute 'Foo'

在重命名 persist.py 模块之后,也会发生类似的错误:

清单 14. 试图装入一个被重命名的 persist.py 模块的经过 pickle 的实例

>>> import cPickle as pickle

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

>>> foo = pickle.load(f)

Traceback (most recent call last):

File "", line 1, in ?

ImportError: No module named persist

我们会在下面模式改进这一节提供一些技术来管理这类更改,而不会破坏现有的 pickle。

前面提到对一些对象类型(譬如,文件对象)不能进行 pickle。处理这种不能 pickle 的对象的实例属性时可以使用特殊的方法(_getstate_() 和 _setstate_())来修改类实例的状态。这里有一个 Foo 类的示例,我们已经对它进行了修改以处理文件对象属性:

清单 15. 处理不能 pickle 的实例属性

class Foo(object):

def __init__(self, value, filename):

self.value = value

self.logfile = file(filename, 'w')

def __getstate__(self):

"""Return state values to be pickled."""

f = self.logfile

return (self.value, f.name, f.tell())

def __setstate__(self, state):

"""Restore state from the unpickled state values."""

self.value, name, position = state

f = file(name, 'w')

f.seek(position)

self.logfile = f

pickle Foo 的实例时,Python 将只 pickle 当它调用该实例的 _getstate_() 方法时返回给它的值。类似的,在 unpickle 时,Python 将提供经过 unpickle 的值作为参数传递给实例的 _setstate_() 方法。在 _setstate_() 方法内,可以根据经过 pickle 的名称和位置信息来重建文件对象,并将该文件对象分配给这个实例的 logfile 属性。

共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