目的:Python對(duì)象序列化
可用性:pickle最少1.4版本,cPickle 1.5版本以上
pickle
模塊實(shí)現(xiàn)了1種算法,將任意1個(gè)Python對(duì)象轉(zhuǎn)化成1系列字節(jié)(byets)。此進(jìn)程也調(diào)用了serializing
對(duì)象。代表對(duì)象的字節(jié)流以后可以被傳輸或存儲(chǔ),再重構(gòu)后創(chuàng)建1個(gè)具有相同特點(diǎn)(the
same characteristics)的新的對(duì)象。
cPickle
使用C而不是Python,實(shí)現(xiàn)了相同的算法。這比Python實(shí)現(xiàn)要快好幾倍,但是它不允許用戶從Pickle派生子類。如果子類對(duì)你的使用來講無關(guān)緊要,那末cPickle是個(gè)更好的選擇。
正告:本文檔直接說明,pickle不提供安全保證。如果你在多線程通訊(inter-process communication)或數(shù)據(jù)存儲(chǔ)或存儲(chǔ)數(shù)據(jù)中使用pickle,1定要謹(jǐn)慎。請(qǐng)勿信任你不能肯定為安全的數(shù)據(jù)。
如平常1樣,嘗試導(dǎo)入cPickle,給它賦予1個(gè)別名“pickle”。如果由于某些緣由導(dǎo)入失敗,退而求其次到Python的原生(native)實(shí)現(xiàn)pickle模塊。如果cPickle可用,能給你提供1個(gè)更快速的履行,否則只能是輕便的履行(the portable implementation)。
try:
import cPickle as pickle
except:
import pickle
第1個(gè)例子將1種數(shù)據(jù)結(jié)構(gòu)編碼成1個(gè)字符串,然后把該字符串打印至控制臺(tái)。使用1種包括所有原生類型(native types)的數(shù)據(jù)結(jié)構(gòu)。任何類型的實(shí)例都可被腌漬(pickled,譯者注:模塊名稱pickle的中文含義為腌菜),在稍后的例子中會(huì)演示。使用pickle.dumps()
來創(chuàng)建1個(gè)表示該對(duì)象值的字符串。
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默許僅由ASCII字符組成。也能夠使用更高效的2進(jìn)制格式(binary format),只是由于在打印的時(shí)候更容易于理解,本頁的所有例子都使用ASCII輸出。
$ 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.
數(shù)據(jù)被序列化以后,你可以將它們寫入文件、套接字、管道等等中。以后你也能夠從文件中讀取出來、將它反腌漬(unpickled)而構(gòu)造1個(gè)具有相同值得新對(duì)象。
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)
如你所見,這個(gè)新構(gòu)造的對(duì)象與原對(duì)象相同,但并不是同1對(duì)象。這不足為奇。
$ 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還提供1對(duì)用在類文件流(file-like
streams)的轉(zhuǎn)化函數(shù)。可以往1個(gè)流中寫對(duì)個(gè)對(duì)象,然后從流中把它們讀取出來,此進(jìn)程不需要預(yù)先寫入的對(duì)象有幾個(gè)、它們多大。
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'))
# 使用StringIO摹擬1個(gè)文件
out_s = StringIO()
# 寫入該流
for o in data:
print 'WRITING: %s (%s)' % (o.name, o.name_backwards)
pickle.dump(o, out_s)
out_s.flush()
# 建立1個(gè)可讀流
in_s = StringIO(out_s.getvalue())
# 讀數(shù)據(jù)
while True:
try:
o = pickle.load(in_s)
except EOFError:
break
else:
print 'READ: %s (%s)' % (o.name, o.name_backwards)
這個(gè)例子使用SringIO緩存器(buffer)摹擬流,所以在建立可讀流的時(shí)候我們玩了1把。1個(gè)簡(jiǎn)單數(shù)據(jù)庫的格式化也能夠使用pickles來存儲(chǔ)對(duì)象,只是shelve
與之工作更加簡(jiǎn)便。
$ python pickle_stream.py
WRITING: pickle (elkcip)
WRITING: cPickle (elkciPc)
WRITING: last (tsal)
READ: pickle (elkcip)
READ: cPickle (elkciPc)
READ: last (tsal)
除存儲(chǔ)數(shù)據(jù),pickles在進(jìn)程間通訊(inter-process communication)中也非常稱手。例如,使用os.fork()
和os.pipe()
可以創(chuàng)建工作者進(jìn)程(worker
processes),從1個(gè)管道(pipe)讀取作業(yè)指令(job instruction)然后將結(jié)果寫入另外一個(gè)管道。管理工作者池(worker pool)和將作業(yè)送入、接受響應(yīng)(response)的核心代碼可被重用,由于作業(yè)和響應(yīng)其實(shí)不屬于某個(gè)特定類中。如果你使用管道或套接字(sockets),在通過連至另外一端(end)的連接傾倒(dumps)所有對(duì)象、推送數(shù)據(jù)以后,別忘了沖洗(flush)。如果你想寫自己的工作者池管理器,請(qǐng)看multiprocessing
。