从这篇文章粗略翻译的pickle and cPicklepython
pickle模块能够实现任意的Python对象转换为一系列字节(即序列化对象)的算法。这些字节流能够 被传输或存储,接着也能够重构为一个和原先对象具备相同特征的新对象。算法
cPickle模块实现了一样的算法,但它是用c而不是python。所以,它比python实现的快上好几倍, 可是不容许使用者去继承Pickle。若是继承对于你的使用不是很重要,那么你大可使用cPickle。数据库
Woring: pickle的文档明确的代表它不提供安全保证。因此慎用pickle来做为内部进程通讯或者数
据存储,也不要相信那些你不能验证安全性的数据。安全
一般优先试用 cPickle,只有当 cPickle 没法正常 import 的时候,采用 pickle 来替代。bash
try: import cPickle as pickle except: import pickle
第一个示例是将数据结构编码为字符串,而后输出到控制台。例子中数据结构彻底由基本类型组成。pickle 能够编码任意类的实例,就像下面栗子中演示的那样:用 pickle.dumps() 来建立对象的字符串表示。数据结构
try: import cPickle as pickle except: import pickle import pprint data = [ { 'a':'A', 'b':2, 'c':3.0 } ] print 'DATA:', pprint.pprint(data) data_string = pickle.dumps(data) print 'PICKLE:', data_string
pickle 默认试用 ASSCII 字符串来进行编码解码。也支持效率更高的二进制格式,可是下面的例子为了方便阅读,仍是使用了 ASSCII 码。app
$ python pickle_string.py DATA:[{'a': 'A', 'b': 2, 'c': 3.0}] PICKLE: (lp1 (dp2 S'a' S'A' sS'c' F3 sS'b' I2 sa.
数据被序列化以后,你就能够将他写入文件、socket、pipe、etc.而后你能够读取文件并unpickle 这些数据来构造一个新的对象。socket
try: import cPickle as pickle except: import pickle import pprint data1 = [ { 'a':'A', 'b':2, 'c':3.0 } ] print 'BEFORE:', pprint.pprint(data1) data1_string = pickle.dumps(data1) data2 = pickle.loads(data1_string) print 'AFTER:', pprint.pprint(data2) print 'SAME?:', (data1 is data2) print 'EQUAL?:', (data1 == data2)
如同例子中演示的那样,新的对象与以前的对象相等,可是并非同一个对象。编码
$ python pickle_unpickle.py BEFORE:[{'a': 'A', 'b': 2, 'c': 3.0}] AFTER:[{'a': 'A', 'b': 2, 'c': 3.0}] SAME?: False EQUAL?: True
除了 dumps() 跟 loads(), pickle 还有其余比较方便的方法来操做类文件流。能够同时写入多个对象到一个 stream 中,而后对象数量与大小的时候从 stream 读取他们。命令行
try: import cPickle as pickle except: import pickle import pprint from StringIO import StringIO class SimpleObject(object): def __init__(self, name): self.name = name l = list(name) l.reverse() self.name_backwards = ''.join(l) return data = [] data.append(SimpleObject('pickle')) data.append(SimpleObject('cPickle')) data.append(SimpleObject('last')) # Simulate a file with StringIO out_s = StringIO() # Write to the stream for o in data: print 'WRITING: %s (%s)' % (o.name, o.name_backwards) pickle.dump(o, out_s) out_s.flush() # Set up a read-able stream in_s = StringIO(out_s.getvalue()) # Read the data while True: try: o = pickle.load(in_s) except EOFError: break else: print 'READ: %s (%s)' % (o.name, o.name_backwards)
上面例子中使用了 StringIO 缓冲区来模拟streams,这样咱们在创建可读流的时候能够玩一些技巧。一些接单的数据库格式也可使用 pickles 来存储数据,固然,若是试用 shelve 来存储会更加简单。
$ python pickle_stream.py WRITING: pickle (elkcip) WRITING: cPickle (elkciPc) WRITING: last (tsal) READ: pickle (elkcip) READ: cPickle (elkciPc) READ: last (tsal)
除了存储数据,pickles 用来作内部通讯的机会也不少。举个例子:用 os.fork() 和 os.pipe() 能够创建一个工做进程,而后这个进程会从管道中读取数据并把结果传递给另一个管道。由于这些代码是用来管理worker pool 跟 发送任务跟接受任务的,没有什么特殊的内容,因此这些核心代码能够被拿来重复利用。若是你在试用 pipe 或者 sockets,那么在 dumping完对象以后,不要忘记刷新它们并经过其间的链接将数据推送到另一个进程。若是你不想本身写 worker pool manager 的话,能够看一下multiprocessing
。
须要注意的是,在序列化实例的时候,咱们只是对于数据来进行序列化,而没法对类的定义进行序列化。
下面的栗子:
try: import cPickle as pickle except: import pickle import sys class SimpleObject(object): def __init__(self, name): self.name = name l = list(name) l.reverse() self.name_backwards = ''.join(l) return if __name__ == '__main__': data = [] data.append(SimpleObject('pickle')) data.append(SimpleObject('cPickle')) data.append(SimpleObject('last')) try: filename = sys.argv[1] except IndexError: raise RuntimeError('Please specify a filename as an argument to %s' % sys.argv[0]) out_s = open(filename, 'wb') try: # Write to the stream for o in data: print 'WRITING: %s (%s)' % (o.name, o.name_backwards) pickle.dump(o, out_s) finally: out_s.close()
运行的时候,这个脚本会以命令行中给出的参数建立一个文件。
$ python pickle_dump_to_file_1.py test.dat WRITING: pickle (elkcip) WRITING: cPickle (elkciPc) WRITING: last (tsal)
下面是一个会报错的栗子:
try: import cPickle as pickle except: import pickle import pprint from StringIO import StringIO import sys try: filename = sys.argv[1] except IndexError: raise RuntimeError('Please specify a filename as an argument to %s' % sys.argv[0]) in_s = open(filename, 'rb') try: # Read the data while True: try: o = pickle.load(in_s) except EOFError: break else: print 'READ: %s (%s)' % (o.name, o.name_backwards) finally: in_s.close()
这个报错是由于没有SimpleObject
类。
$ python pickle_load_from_file_1.py test.dat Traceback (most recent call last): File "pickle_load_from_file_1.py", line 52, in <module> o = pickle.load(in_s) AttributeError: 'module' object has no attribute 'SimpleObject'
咱们经过从原来的脚本中import SimpleObject来修正上面的错误。
在上面文件中的增长下面一行:
from pickle_dump_to_file_1 import SimpleObject
$ python pickle_load_from_file_2.py test.dat READ: pickle (elkcip) READ: cPickle (elkciPc) READ: last (tsal)
像sockets, file handles, database connections ...
这些数据类型是没法被序列化的,咱们在处理相似数据类型的时候不得不特殊处理。而利用pickle protocol 则能够控制序列化的细节。
class Data(object): def __init__(self, x, y): self._x = x self._y = y def __getstate__(self): d = self.__dict__.copy() del d["_y"] return d def __setstate__(self, state): self.__dict__.update(state) d = Data(10, 20) s = cPickle.dumps(d, 2) d2 = cPickle.loads(s) ##d2.__dict__ ##{'_x': 10}