Linux编程之序列化存储Python对象(下)(2)
文章作者 100test 发表时间 2007:03:14 16:31:46
来源 100Test.Com百考试题网
类实例
与 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 模块,它包含以下新型类的定义:
class Foo(object):
def __init__(self, value):
self.value = value |
清单 11. 新型类的定义
现在可以 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.
>>> |
清单 12. pickle Foo 实例
可以看到这个类的名称 Foo 和全限定的模块名称 Orbtech.examples.persist 都存储在 pickle 中。如果将这个实例 pickle 成一个文件,稍后再 unpickle 它或在另一台机器上 unpickle,则 Python 会试图导入 Orbtech.examples.persist 模块,如果不能导入,则会抛出异常。如果重命名该类和该模块或者将该模块移到另一个目录,则也会发生类似的错误。
这里有一个 Python 发出错误消息的示例,当我们重命名 Foo 类,然后试图装入先前进行过 pickle 的 Foo 实例时会发生该错误:
>>> 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 |
清单 13. 试图装入一个被重命名的 Foo 类的经过 pickle 的实例
在重命名 persist.py 模块之后,也会发生类似的错误:
>>> 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 |
清单 14. 试图装入一个被重命名的 persist.py 模块的经过 pickle 的实例
我们会在下面模式改进这一节提供一些技术来管理这类更改,而不会破坏现有的 pickle。