引用部分来自:http://blog.csdn.net/jq0123/article/details/4319589
http://www.cnblogs.com/cobbliu/archive/2012/09/04/2670178.html
Programming Python, 3rd Edition 翻译 最新版本见:http://wiki.woodpecker.org.cn/moin/PP3eD
持久性就是指保持对象,甚至在多次执行同一程序之间也保持对象。
pickle是为了序列化/反序列化一个对象的,可以把一个对象持久化存储。 比如你有一个对象,想下次运行程序的时候直接用,可以直接用pickle打包存到硬盘上。或者你想把一个对象传给网络上的其他程序,可以用pickle打包,然后传过去,那边的python程序用pickle反序列化,就可以用了。 用法上,它主要有两个函数:load和dump,load是从序列化之后的数据中解出来,dump是把对象序列化。
Python系统的标准部件,pickle模块。它可以将几乎任意的Python内存对象,转换为单一线性的字符串格式,**使之适于无格式文件存储**,或在可靠来源之间跨越网络套接口传输等等,并可反向转换。这种从对象到字符串的转换通常被称为**序列化**(serialization):将内存中的任意数据结构映射为串行字符串形式。 对象的字符串表达由于其线性的格式,有时也被称为字节流。它包含了原始内存中对象的所有内容和引用结构。当对象后来从其字节串重建时,内存中新建的对象与原对象具有相同的结构和值,但位于不同的内存地址。该重建对象实际上是**原对象的复制**。 Pickle可用于几乎所有的Python数据类型:数字、列表、字典、类实例、嵌套结构,等等,因此**它是存储数据的通用方法**。因为pickle包含的是Python本地对象,所以几乎没有数据库的API;对象存储与处理及后来的提取用的都是通常的Python语法。第一次听到pickle,可能觉得有点复杂,但好消息是,Python隐藏了所有从对象到字符串转换的复杂性。事实上,pickle模块的接口简单易用,简直令人难以置信。例如,要pickle对象到一个序列化字符串,我们可以生成一个pickler,并调用其方法,或使用模块中的便捷函数来达到相同的效果:
生成一个新的pickler,用来pickle到一个打开的输出文件对象file:
P = pickle.Pickler( file)写一个对象到pickler的文件/流:
P.dump( object)等同于上两个调用的组合:pickle对象到一个打开的文件:
pickle.dump( object, file)返回一个字符串作为已pickle对象的表达:
string = pickle.dumps( object)从一个序列化字符串unpickle回原始对象是类似的,可以用对象也可以用便捷函数接口:
生成一个unpickler,用来从一个打开的文件对象file unpickle:
U = pickle.Unpickler( file)从unpickler的文件/流读取一个对象:
object = U.load( )等同于上两个调用的组合:从一个打开的文件unpickle一个对象:
object = pickle.load( file)从字符串读取一个对象,而不是从文件:
object = pickle.loads( string)Pickler和Unpickler是导出类。在上述所有情况下,file是个已打开的文件对象,或者是实现了以下文件对象属性的任何对象:
Pickler会调用文件的write方法,参数是个字符串。
Unpickler会调用文件的read方法,参数是字节数,以及readline,无参数。
任何提供这些属性的对象都可以作为file参数传入。特别是,file可以是一个提供了读/写方法的Python类实例(即预期的类似文件的接口)。这让您可以用类映射pickle流到内存对象,并可任意使用。例
该挂钩也可以让您通过网络传输Python对象,只要封装套接口,使之看上去像发送端pickle调用中的文件,以及像接收端unpickle调用中的文件。事实上,对一些人来说,pickle Python对象并在一个值得信赖的网络上传输,是替代如SOAP和XML-RPC之类网络传输协议的一个简单方法;只要通信的两端都有Python(被pickle的对象是用Python专有的格式表达的,而不是用XML文本)。
注:该文本 pickle 格式很简单,这里就不解释了。事实上,在 pickle 模块中记录了所有使用的约定。我们还应该指出,在我们的示例中使用的都是简单对象,因此使用二进制 pickle 格式不会在节省空间上显示出太大的效率。然而,在实际使用复杂对象的系统中,您会看到,使用二进制格式可以在大小和速度方面带来显著的改进。
这些示例用到了 dump() 和 load() ,它们使用文件和类似文件的对象。这些函数的操作非常类似于我们刚才所看到的 dumps() 和 loads() ,区别在于它们还有另一种能力 — dump() 函数能一个接着一个地将几个对象转储到同一个文件。随后调用 load() 来以同样的顺序检索这些对象。清单 2 显示了这种能力的实际应用:
>>> 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()在 Python 中,变量是对象的引用。同时,也可以用多个变量引用同一个对象。经证明,Python 在用经过 pickle 的对象维护这种行为方面丝毫没有困难
>>> 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]注意,如果分别 pickle 每个对象,而不是在一个元组中一起 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 的。例如,Python 不能 pickle 文件对象(或者任何带有对文件对象引用的对象),因为 Python 在 unpickle 时不能保证它可以重建该文件的状态(另一个示例比较难懂,在这类文章中不值得提出来)。试图 pickle 文件对象会导致以下错误:
>>> f = file('temp.pkl', 'w') >>> p = pickle.dumps(f) Traceback (most recent call last): File "<input>", 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在最近的Python版本中,pickler推出了协议的概念:pickle数据的保存格式。通过pickle调用时传入一个额外的参数,可指定所需的协议(但unpickle调用不需要:协议是自动从已pickle的数据确定的):
pickle.dump(object, file, protocol)
Pickle数据可以按文本协议或二进制协议产生。默认情况下,存储协议是文本协议(也称为0号协议)。在文本模式下,用来存储pickle对象的文件可以用文本模式打开,如上述的例子,并且pickle的数据是可打印的ASCII文本,并且是可读的(这基本上是对堆栈机实现的指示)。
其他协议(1号和2号协议 )以二进制格式存储pickle数据,并要求文件以二进制模式打开(例如:rb、wb)。1号协议是原始二进制格式;2号协议是Python 2.3增加的,它改善了对新型类pickle的支持。二进制格式效率更高一点,但它无法进行查看。旧的pickle调用有一个选项,即bin参数,现已被归入使用大于0的协议。pickle模块还提供了一个HIGHEST_PROTOCOL变量,传入它可以自动选择最大的协议值。
注意:如果您使用默认的文本协议,以后请务必以文本模式打开pickle文件。在一些平台上,因为Windows的行尾格式不同,以二进制模式打开文本数据可能会导致unpickle错误:
>>> f = open('temp', 'w') # text mode file on Windows >>> pickle.dump(('ex', 'parrot'), f) # use default text protocol >>> f.close( ) >>> >>> pickle.load(open('temp', 'r')) # OK in text mode ('ex', 'parrot') >>> pickle.load(open('temp', 'rb')) # fails in binary Traceback (most recent call last): File "<pyshell#337>", line 1, in -toplevel- pickle.load(open('temp', 'rb')) ...lines deleted... ValueError: insecure string pickle回避这个潜在问题的方法之一是,总是使用二进制模式的文件,即使是用文本pickle协议。至少对于二进制pickler协议(高于默认0),您必须以二进制模式打开文件,所以这不是一个坏习惯:
>>> f = open('temp', 'wb') # create in binary mode >>> pickle.dump(('ex', 'parrot'), f) # use text protocol >>> f.close( ) >>> >>> pickle.load(open('temp', 'rb')) ('ex', 'parrot') >>> pickle.load(open('temp', 'r')) ('ex', 'parrot')请参考Python库手册,以了解更多pickler的信息。另外,请查阅marshal,它也是一个序列化对象的模块,但只能处理简单对象类型。pickle比marshal更通用,并通常是首选。
而当你翻看(或点击)Python手册时,请一定也要看看cPickle模块的条目,它是pickle的C语言实现,性能上更快。您可以显式导入cPickle替代pickle,以大幅提升速度;其主要的限制是,你不能继承该版本的Pickle和Unpickle,因为它们是函数,而不是类(多数程序并不要求它们是类)。pickle和cPickle模块使用兼容的数据格式,所以它们可以互换使用。
如果您的Python中有shelve模块,它会自动选用cPickle模块,而不是pickle,以达到更快的序列化。我还没有解释过shelve,但我马上就会讲到它。