pickle --- Python 物件序列化¶
原始碼:Lib/pickle.py
pickle 模組實作的是一個在二進位層級上對 Python 物件進行序列化(serialize)或去序列化(de-serialize)。"Pickling" 用於專門指摘將一個 Python 物件轉換為一個二進位串流的過程,"unpickling" 則相反,指的是將一個(來自 binary file 或 bytes-like object 的)二進位串流轉換回 Python 物件的過程。Pickling(和 unpickling)的過程也可能被稱作 "serialization", "marshalling," [1] 或 "flattening"。不過,為了避免混淆,本文件將統一稱作封裝(pickling)、拆封(unpickling)。
警告
pickle 模組並不安全,切記只拆封你信任的資料。
pickle 封包是有可能被建立來在拆封的時候執行任意惡意程式碼的。絕對不要拆封任何你無法信任其來源、或可能被修改過的 pickle 封包。
建議你可以使用 hmac 模組來簽署這個封包,以確保其未被修改過。
如果你在處理不受信任的資料,其他比較安全的序列化格式(例如 json)可能會更適合。請參照 See 和 json 的比較 的說明。
和其他 Python 模組的關係¶
和 marshal 的比較¶
Python 有另一個比較原始的序列化模組叫 marshal,不過其設計目的是為了支援 Python 的預編譯功能 .pyc 的運作。總地來說,請盡可能地使用 pickle,沒事不要用 marshal。
pickle 和 marshal 有幾個明顯不同的地方:
和 json 的比較¶
pickle 協定和 JSON (JavaScript Object Notation) 有一些根本上的不同:
JSON 以文字形式作為序列化的輸出(輸出 unicode 文字,但大多數又會被編碼為
UTF-8),而 pickle 則是以二進位形式作為序列化的輸出;JSON 是人類可讀的,而 pickle 則無法;
JSON 具有高互通性(interoperability)且在 Python 以外的環境也被大量利用,但 pickle 只能在 Python 內使用。
預設狀態下的 JSON 只能紀錄一小部份的 Python 內建型別,且無法紀錄自訂類別;但透過 Python 的自省措施,pickle 可以紀錄絕大多數的 Python 型別(其他比較複雜的狀況也可以透過實作 specific object APIs 來解決);
去序列化不安全的 JSON 不會產生任意程式執行的風險,但去序列化不安全的 pickle 會。
也參考
json module: 是標準函式庫的一部分,可讓使用者進行 JSON 的序列化與去序列化。
資料串流格式¶
pickle 使用的資料格式是針對 Python 而設計的。好處是他不會受到外部標準(像是 JSON,無法紀錄指標共用)的限制;不過這也代表其他不是 Python 的程式可能無法重建 pickle 封裝的 Python 物件。
以預設設定來說,pickle 使用相對緊湊的二進位形式來儲存資料。如果你需要盡可能地縮小檔案大小,你可以壓縮封裝的資料。
pickletools 含有工具可分析 pickle 所產生的資料流。pickletools 的源始碼詳細地記載了所有 pickle 協定的操作碼(opcode)。
截至目前為止,共有六種不同版本的協定可用於封裝 pickle。數字越大版本代表你需要使用越新的 Python 版本來拆封相應的 pickle 封裝。
版本 0 的協定是最初「人類可讀」的版本,且可以向前支援早期版本的 Python。
版本 1 的協定使用舊的二進位格式,一樣能向前支援早期版本的 Python。
版本 2 的協定在 Python 2.3 中初次被引入。其可提供更高效率的 new-style classes 封裝過程。請參閱 PEP 307 以了解版本 2 帶來的改進。
版本 3 的協定在 Python 3.0 被新增。現在能支援封裝
bytes的物件且無法被 2.x 版本的 Python 拆封。在 3.0~3.7 的 Python 預設使用 3 版協定。版本 4 的協定在 Python 3.4 被新增。現在能支援超大物件的封裝、更多種型別的物件以及針對部份資料格式的儲存進行最佳化。從 Python 3.8 到 3.13,預設使用第 4 版協定。請參閱 PEP 3154 以了解第 4 版協定改進的細節。
版本 5 的協定在 Python 3.8 被新增。現在能支援帶外資料(Out-of-band data)並加速帶內資料的處理速度。自 3.14 起這是預設使用的協定。請參閱 PEP 574 以了解第 5 版協定改進的細節。
備註
資料序列化是一個比資料持久化更早出現的概念;雖然 pickle 可以讀寫檔案物件,但它並不處理命名持久物件的問題,也不處理對持久物件的並行存取、一個更棘手的問題。pickle 模組可以將複雜物件轉換成位元組串流,也可以將位元組串流轉換回具有相同原始內部結構的物件。對這些位元組串流最常見的處理方式是將它們寫入檔案中,但也可以將它們透過網路傳送或儲存在一個資料庫中。shelve 模組提供了一個簡單的介面來讓使用者在 DBM 風格的資料庫檔案中對物件進行封裝和拆封的操作。
模組介面¶
想要序列化一個物件,你只需要呼叫 dumps() 函式。而當你想要去序列化一個資料流時,你只需要呼叫 loads() 即可。不過,若你希望能各自對序列化和去序列化的過程中有更多的掌控度,你可以自訂一個 Pickler 或 Unpickler 物件。
pickle 模組提供以下常數:
- pickle.DEFAULT_PROTOCOL¶
一個整數,用於 pickle 的預設 協定版本。可能小於
HIGHEST_PROTOCOL。目前預設協定是 5,在 Python 3.8 中引入,與之前的版本不相容。此版本引入了對 out-of-band buffer 的支援,其中 PEP 3118 相容的資料可以與主要 pickle 串流分開傳輸。在 3.0 版的變更: 預設協定版本為 3。
在 3.8 版的變更: 預設協定版本為 4。
在 3.14 版的變更: 預設協定是 5。
pickle 模組提供下列函式來簡化封裝的過程:
- pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)¶
將被封裝成 pickle 形式的物件 obj 寫入到已開啟的file object file。這等效於
Pickler(file, protocol).dump(obj)。引數 file、protocol、fix_imports 和 buffer_callback 的意義與
Pickler建構式中的相同。在 3.8 版的變更: 新增 buffer_callback 引數。
- pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)¶
將被封裝為 pickle 形式的物件 obj 以
bytes類別回傳,而非寫入進檔案。引數 protocol、fix_imports 和 buffer_callback 的意義和
Pickler建構式中的相同。在 3.8 版的變更: 新增 buffer_callback 引數。
- pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)¶
從已開啟的 檔案物件 file 中讀取已序列化的物件,並傳回其重建後的物件階層。這相當於呼叫
Unpickler(file).load()。模組會自動偵測 pickle 封包所使用的協定版本,所以無須另外指定。超出 pickle 封包表示範圍的位元組將被忽略。
引數 file、fix_imports、encoding、errors、strict 和 buffers 的意義和
Unpickler建構式中的相同。在 3.8 版的變更: 新增 buffer 引數。
- pickle.loads(data, /, *, fix_imports=True, encoding='ASCII', errors=