Python模塊學習 ---- pickle, cPickle 對象序列化/反序列化

上次學習過marshal模塊用於序列化和反序列化,但marshal的功能比較薄弱,只支持部份內置數據類型的序列化/反序列化,對於用戶自定義的類型就無能爲力,同時marshal不支持自引用(遞歸引用)的對象的序列化。因此直接使用marshal來序列化/反序列化可能不是很方便。還好,python標準庫提供了功能更增強大且更加安全的pickle和cPickle模塊。python

  cPickle模塊是使用C語言實現的,因此在運行效率上比pickle要高。可是cPickle模塊中定義的類型不能被繼承(其實大多數時候,咱們不須要從這些類型中繼承。)。cPickle和pickle的序列化/反序列化規則是同樣的,咱們可使用pickle序列化一個對象,而後使用cPickle來反序列化。同時,這兩個模塊在處理自引用類型時會變得更加「聰明」,它不會無限制的遞歸序列化自引用對象,對於同一對象的屢次引用,它只會序列化一次。例如:安全

import marshal, pickle
 
list = [1]
list.append(list)
byt1 = marshal.dumps(list) #出錯, 無限制的遞歸序列化
byt2 = pickle.dumps(list) #No problem

 

pickle的序列化規則

  Python規範(Python-specific)提供了pickle的序列化規則。這就沒必要擔憂不一樣版本的Python之間序列化兼容性問題。默認狀況下,pickle的序列化是基於文本的,咱們能夠直接用文本編輯器查看序列化的文本。咱們也能夠序列成二進制格式的數據,這樣的結果體積會更小。更詳細的內容,能夠參考Python手冊pickle模塊。app

  下面就開始使用pickle吧~編輯器

pickle.dump(obj, file[, protocol])

  序列化對象,並將結果數據流寫入到文件對象中。參數protocol是序列化模式,默認值爲0,表示以文本的形式序列化。protocol的值還能夠是1或2,表示以二進制的形式序列化。學習

pickle.load(file)

  反序列化對象。將文件中的數據解析爲一個Python對象。下面經過一個簡單的例子來演示上面兩個方法的使用:spa

#coding=gbk
 
import pickle, StringIO
 
class Person(object):
    '''自定義類型。
    '''
    def __init__(self, name, address):
        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的定義。對象

pickle.dumps(obj[, protocol])

pickle.loads(string)

  咱們也能夠直接獲取序列化後的數據流,或者直接從數據流反序列化。方法dumps與loads就完成這樣的功能。dumps返回序列化後的數據流,loads返回的序列化生成的對象。繼承

  python模塊中還定義了兩個類,分別用來序列化、反序列化對象。遞歸

class pickle.Pickler(file[, protocal]):

  該類用於序列化對象。參數file是一個類文件對象(file-like object),用於保存序列化結果。可選參數表示序列化模式。它定義了兩個方法:ci

dump(obj):

  將對象序列化,並保存到類文件對象中。參數obj是要序列化的對象。

clear_memo()

  清空pickler的「備忘」。使用Pickler實例在序列化對象的時候,它會「記住」已經被序列化的對象引用,因此對同一對象屢次調用dump(obj),pickler不會「傻傻」的去屢次序列化。下面是一個簡單的例子:

#coding=gbk
import pickle, StringIO
 
class Person(object):
    '''自定義類型。
    '''
    def __init__(self, name, address):
        self.name = name
        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   

 

class pickle.Unpickler(file):

  該類用於反序列化對象。參數file是一個類文件(file-like object)對象,Unpickler從該參數中獲取數據進行反序列化。

load():

  反序列化對象。該方法會根據已經序列化的數據流,自動選擇合適的反序列化模式。

#.... 接上個例子中的代碼
 
fle.seek(0)
unpick = pickle.Unpickler(fle)
print unpick.load()
 

  上面介紹了pickle模塊的基本使用,但和marshal同樣,並非全部的類型均可以經過pickle序列化的。例如對於一個嵌套的類型,使用pickle序列化就失敗。例如:

class A(object):
    class B(object):
        def __init__(self, name):
            self.name = name
    
    def __init__(self):
        print 'init A'
 
= A.B("my name")
10  print b
11  = pickle.dumps(b, 0) #失敗哦
12  print pickle.loads(c)

  關於pickle支持的序列化類型,能夠參考Python手冊。

  Python手冊中的pickle模塊,介紹了更高級的主題,例如自定義序列化過程。有時間再和你們分享。

相關文章
相關標籤/搜索