從這篇文章粗略翻譯的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}