Python模組學習 :pickle, cPickle 物件序列化/反序列化

發表於2015-05-26

上次學習過marshal模組用於序列化和反序列化,但marshal的功能比較薄弱,只支援部分內建資料型別的序列化/反序列化,對於使用者自定義的型別就無能為力,同時marshal不支援自引用(遞迴引用)的物件的序列化。所以直接使用marshal來序列化/反序列化可能不是很方便。還好,python標準庫提供了功能更加強大且更加安全的pickle和cPickle模組。

cPickle模組是使用C語言實現的,所以在執行效率上比pickle要高。但是cPickle模組中定義的型別不能被繼承(其實大多數時候,我們不需要從這些型別中繼承。)。cPickle和pickle的序列化/反序列化規則是一樣的,我們可以使用pickle序列化一個物件,然後使用cPickle來反序列化。同時,這兩個模組在處理自引用型別時會變得更加“聰明”,它不會無限制的遞迴序列化自引用物件,對於同一物件的多次引用,它只會序列化一次。例如:

pickle的序列化規則

Python規範(Python-specific)提供了pickle的序列化規則。這就不必擔心不同版本的Python之間序列化相容性問題。預設情況下,pickle的序列化是基於文字的,我們可以直接用文字編輯器檢視序列化的文字。我們也可以序列成二進位制格式的資料,這樣的結果體積會更小。更詳細的內容,可以參考Python手冊pickle模組。

下面就開始使用pickle吧~

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

序列化物件,並將結果資料流寫入到檔案物件中。引數protocol是序列化模式,預設值為0,表示以文字的形式序列化。protocol的值還可以是1或2,表示以二進位制的形式序列化。

pickle.load(file)

反序列化物件。將檔案中的資料解析為一個Python物件。下面通過一個簡單的例子來演示上面兩個方法的使用:

注意:在反序列化的時候,必須能找到對應類的定義,否則反序列化將失敗。在上面的例子中,如果取消#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),用於儲存序列化結果。可選參數列示序列化模式。它定義了兩個方法:

dump(obj):

將物件序列化,並儲存到類檔案物件中。引數obj是要序列化的物件。

clear_memo()

清空pickler的“備忘”。使用Pickler例項在序列化物件的時候,它會“記住”已經被序列化的物件引用,所以對同一物件多次呼叫dump(obj),pickler不會“傻傻”的去多次序列化。下面是一個簡單的例子:

class pickle.Unpickler(file):

該類用於反序列化物件。引數file是一個類檔案(file-like object)物件,Unpickler從該引數中獲取資料進行反序列化。

load():

反序列化物件。該方法會根據已經序列化的資料流,自動選擇合適的反序列化模式。

上面介紹了pickle模組的基本使用,但和marshal一樣,並不是所有的型別都可以通過pickle序列化的。例如對於一個巢狀的型別,使用pickle序列化就失敗。例如:

關於pickle支援的序列化型別,可以參考Python手冊。

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

相關文章