上次學習過marshal模塊用於序列化和反序列化,但marshal的功能比較薄弱,只支持部份內置數據類型的序列化/反序列化,對於用戶自定義的類型就無能爲力,同時marshal不支持自引用(遞歸引用)的對象的序列化。因此直接使用marshal來序列化/反序列化可能不是很方便。還好,python標準庫提供了功能更增強大且更加安全的pickle和cPickle模塊。python
cPickle模塊是使用C語言實現的,因此在運行效率上比pickle要高。可是cPickle模塊中定義的類型不能被繼承(其實大多數時候,咱們不須要從這些類型中繼承。)。cPickle和pickle的序列化/反序列化規則是同樣的,咱們可使用pickle序列化一個對象,而後使用cPickle來反序列化。同時,這兩個模塊在處理自引用類型時會變得更加「聰明」,它不會無限制的遞歸序列化自引用對象,對於同一對象的屢次引用,它只會序列化一次。例如:安全
1 | import marshal, pickle |
2 | |
3 | list = [1] |
4 | list.append(list) |
5 | byt1 = marshal.dumps(list) #出錯, 無限制的遞歸序列化 |
6 | byt2 = pickle.dumps(list) #No problem |
Python規範(Python-specific)提供了pickle的序列化規則。這就沒必要擔憂不一樣版本的Python之間序列化兼容性問題。默認狀況下,pickle的序列化是基於文本的,咱們能夠直接用文本編輯器查看序列化的文本。咱們也能夠序列成二進制格式的數據,這樣的結果體積會更小。更詳細的內容,能夠參考Python手冊pickle模塊。app
下面就開始使用pickle吧~編輯器
序列化對象,並將結果數據流寫入到文件對象中。參數protocol是序列化模式,默認值爲0,表示以文本的形式序列化。protocol的值還能夠是1或2,表示以二進制的形式序列化。學習
反序列化對象。將文件中的數據解析爲一個Python對象。下面經過一個簡單的例子來演示上面兩個方法的使用:spa
1 | #coding=gbk |
2 | |
3 | import pickle, StringIO |
4 | |
5 | class Person(object): |
6 | '''自定義類型。 |
7 | ''' |
8 | def __init__(self, name, address): |
9 | self.name = name |
10 | self.address = address |
11 | |
12 | def display(self): |
13 | print 'name:', self.name, 'address:', self.address |
14 | |
15 | jj = Person("JGood", "中國 杭州") |
16 | jj.display() |
17 | file = StringIO.StringIO() |
18 | |
19 | pickle.dump(jj, file, 0) #序列化 |
20 | #print file.getvalue() #打印序列化後的結果 |
#del Person #反序列的時候,必須能找到對應類的定義。不然反序列化操做失敗。 | |
21 | |
22 | file.seek(0) |
23 | jj1 = pickle.load(file) #反序列化 |
24 | jj1.display() |
25 | |
26 | file.close() |
注意:在反序列化的時候,必須能找到對應類的定義,不然反序列化將失敗。在上面的例子中,若是取消#del Person的註釋,在運行時將拋AttributeError異常,提示當前模塊找不到Person的定義。對象
咱們也能夠直接獲取序列化後的數據流,或者直接從數據流反序列化。方法dumps與loads就完成這樣的功能。dumps返回序列化後的數據流,loads返回的序列化生成的對象。繼承
python模塊中還定義了兩個類,分別用來序列化、反序列化對象。遞歸
該類用於序列化對象。參數file是一個類文件對象(file-like object),用於保存序列化結果。可選參數表示序列化模式。它定義了兩個方法:ci
將對象序列化,並保存到類文件對象中。參數obj是要序列化的對象。
清空pickler的「備忘」。使用Pickler實例在序列化對象的時候,它會「記住」已經被序列化的對象引用,因此對同一對象屢次調用dump(obj),pickler不會「傻傻」的去屢次序列化。下面是一個簡單的例子:
1 | #coding=gbk |
2 | import pickle, StringIO |
3 | |
4 | class Person(object): |
5 | '''自定義類型。 |
6 | ''' |
7 | def __init__(self, name, address): |
8 | self.name = name |
9 | self.address = address |
10 | |
11 | def display(self): |
12 | print 'name:', self.name, 'address:', self.address |
13 | |
14 | fle = StringIO.StringIO() |
15 | pick = pickle.Pickler(fle) |
16 | person = Person("JGood", "Hangzhou China") |
17 | |
18 | pick.dump(person) |
19 | val1 = fle.getvalue() |
20 | print len(val1) |
21 | |
22 | pick.clear_memo() #註釋此句,再看看運行結果 |
23 | |
24 | pick.dump(person) #對同一引用對象再次進行序列化 |
25 | val2 = fle.getvalue() |
26 | print len(val2) |
27 | |
28 | #---- 結果 ---- |
29 | #148 |
30 | #296 |
31 | # |
32 | #將這行代碼註釋掉:pick.clear_memo() |
33 | #結果爲: |
34 | #148 |
35 | #152 |
36 |
該類用於反序列化對象。參數file是一個類文件(file-like object)對象,Unpickler從該參數中獲取數據進行反序列化。
反序列化對象。該方法會根據已經序列化的數據流,自動選擇合適的反序列化模式。
1 | #.... 接上個例子中的代碼 |
2 | |
3 | fle.seek(0) |
4 | unpick = pickle.Unpickler(fle) |
5 | print unpick.load() |
6 |
上面介紹了pickle模塊的基本使用,但和marshal同樣,並非全部的類型均可以經過pickle序列化的。例如對於一個嵌套的類型,使用pickle序列化就失敗。例如:
1 | class A(object): |
2 | class B(object): |
3 | def __init__(self, name): |
4 | self.name = name |
5 | |
6 | def __init__(self): |
7 | print 'init A' |
8 | |
9 | b = A.B("my name") |
10 | print b |
11 | c = pickle.dumps(b, 0) #失敗哦 |
12 | print pickle.loads(c) |
關於pickle支持的序列化類型,能夠參考Python手冊。
Python手冊中的pickle模塊,介紹了更高級的主題,例如自定義序列化過程。有時間再和你們分享。