pickle和cPickle:Python對象的序列化(上)

目的:Python對象序列化
可用性:pickle至少1.4版本,cPickle 1.5版本以上html


pickle模塊實現了一種算法,將任意一個Python對象轉化成一系列字節(byets)。此過程也調用了serializing對象。表明對象的字節流以後能夠被傳輸或存儲,再重構後建立一個擁有相同特徵(the same characteristics)的新的對象。python

cPickle使用C而不是Python,實現了相同的算法。這比Python實現要快好幾倍,可是它不容許用戶從Pickle派生子類。若是子類對你的使用來講可有可無,那麼cPickle是個更好的選擇。算法

警告:本文檔直接說明,pickle不提供安全保證。若是你在多線程通訊(inter-process communication)或者數據存儲或存儲數據中使用pickle,必定要當心。請勿信任你不能肯定爲安全的數據。數據庫

導入

如日常同樣,嘗試導入cPickle,給它賦予一個別名「pickle」。若是由於某些緣由導入失敗,退而求其次到Python的原生(native)實現pickle模塊。若是cPickle可用,能給你提供一個更快速的執行,不然只能是輕便的執行(the portable implementation)。緩存

pythontry:
   import cPickle as pickle
except:
   import pickle

編碼和解碼

第一個例子將一種數據結構編碼成一個字符串,而後把該字符串打印至控制檯。使用一種包含全部原生類型(native types)的數據結構。任何類型的實例均可被醃漬(pickled,譯者注:模塊名稱pickle的中文含義爲醃菜),在稍後的例子中會演示。使用pickle.dumps()來建立一個表示該對象值的字符串。安全

pythontry:
    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字符組成。也可使用更高效的二進制格式(binary format),只是由於在打印的時候更易於理解,本頁的全部例子都使用ASCII輸出。數據結構

python$ 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.

數據被序列化之後,你能夠將它們寫入文件、套接字、管道等等中。以後你也能夠從文件中讀取出來、將它反醃漬(unpickled)而構造一個具備相同值得新對象。多線程

pythontry:
    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)

如你所見,這個新構造的對象與原對象相同,但並不是同一對象。這不足爲奇。app

python$ 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還提供一對用在類文件流(file-like streams)的轉化函數。能夠往一個流中寫對個對象,而後從流中把它們讀取出來,此過程不須要預先寫入的對象有幾個、它們多大。socket

pythontry:
    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模擬一個文件
out_s = StringIO()

# 寫入該流
for o in data:
    print 'WRITING: %s (%s)' % (o.name, o.name_backwards)
    pickle.dump(o, out_s)
    out_s.flush()

# 創建一個可讀流
in_s = StringIO(out_s.getvalue())

# 讀數據
while True:
    try:
        o = pickle.load(in_s)
    except EOFError:
        break
    else:
        print 'READ: %s (%s)' % (o.name, o.name_backwards)

這個例子使用SringIO緩存器(buffer)模擬流,因此在創建可讀流的時候咱們玩了一把。一個簡單數據庫的格式化也可使用pickles來存儲對象,只是shelve與之工做更加簡便。

python$ python pickle_stream.py

WRITING: pickle (elkcip)
WRITING: cPickle (elkciPc)
WRITING: last (tsal)
READ: pickle (elkcip)
READ: cPickle (elkciPc)
READ: last (tsal)

除了存儲數據,pickles在進程間通訊(inter-process communication)中也很是稱手。例如,使用os.fork()os.pipe()能夠創立工做者進程(worker processes),從一個管道(pipe)讀取做業指令(job instruction)而後將結果寫入另外一個管道。管理工做者池(worker pool)和將做業送入、接受響應(response)的核心代碼可被重用,由於做業和響應並不屬於某個特定類中。若是你使用管道或者套接字(sockets),在經過連至另外一端(end)的鏈接傾倒(dumps)全部對象、推送數據以後,別忘了沖洗(flush)。若是你想寫本身的工做者池管理器,請看multiprocessing

原文:pickle and cPickle – Python object serialization - Python Module of the Week 的前半部分

相關文章
相關標籤/搜索