[python] pickle 模塊 -- 實現數據簡單存儲 原

今天要給大家介紹的,是 pickle 模塊。通過詞典我們可以知道, pickle 這個詞的意思是“泡菜”。聽了這麼個名字,大家是不是更加疑惑了?難道我們要把程序放進一個缸裏,讓他自己發酵?哈哈,當然不是這樣。

pickle 模塊的產生是爲了解決文件讀取中的一大問題:如何方便地保存和讀取數據。許多時候我們寫入一個文件,只是爲了將數據保存,爲了方便下一個程序讀取它。而一般存儲的文件都是以文本形式,這樣就容易導致互相的不兼容。所以產生了兩種常用的標準存儲形式: CSVJSON 。下面先簡單介紹一下它們:

1. CSV 的原理

CSV 可以較爲方便地存儲一個一維或者二維的列表。它用逗號分隔不同的數據,用換行來表示下一組數據。以下是 Wiki-CSV 上的介紹:

In computing, a comma-separated values (CSV) file is a delimited text file that uses a comma to separate values. A CSV file stores tabular data (numbers and text) in plain text. Each line of the file is a data record. Each record consists of one or more fields, separated by commas. The use of the comma as a field separator is the source of the name for this file format.

CSV 使用起來較爲簡單,python 中也有官方的 CSV 模塊,我們用代碼也可以實現。比如有下面這樣一個 CSV 格式的字符串。

'12,24,46'

在 python 中,我們只需要用到字符串中的 split 方法,便可以實現將數據恢復爲列表:

ls = '12,24,46'.split(',')

但是要將列表轉化爲 CSV 格式就稍微複雜些了。我們常用 ‘,’.join(ls) 這樣的方法將列表轉化爲字符串,但是 join 方法只支持所有元素全部爲字符串的列表,如果列表中有數字等類型就會報錯。而且二維列表就需要循環來輸出每一行。這個實現方法不難,但是代碼有些冗長,所以不貼上來了。如果各位有興趣可以嘗試自己寫一寫。

但是 CSV 的存儲還有一些問題,比如它不能存儲類似於對象/結構體這樣的複雜的類型。而且如果數據中含有逗號這個字符,那麼 CSV 便無法正確地將數據分隔。遇到這樣的問題, JSON 就是另一種解決方案。

2. JSON 與 pickle 的區別

JSON 是一種較爲通用的數據存儲結構,它可以在多種語言之間相互使用。 JSON 的語法較爲複雜,這裏就不再詳細介紹。JSON 能夠實現任意類型的數據存儲,這使得它比 CSV 有更廣的適用性。 python 也帶有 JSON 的官方模塊,也可以比較方便地實現讀取存儲功能,但是對於不多的數據, JSON 便有些“大材小用”了(JSON 相較於 pickle 還有一點優點就是它可以方便地可視化,因爲 pickle 保存後的文件爲二進制格式,無法直接用文本編輯器直接打開;但這樣相對來說 pickle 的文件較爲安全,它被直接打開或是被中途修改的可能性就更小)

然而假如你僅僅只需要在 python 中存儲幾個數據。使用上面兩種方法便也有些過於複雜。如果你不需要用到通用的數據存儲, pickle 就是一個最好的選擇。

3. pickle 的常用函數

pickle 模塊只需要用簡單的 dump(obj, file) 函數就可以實現寫入文件,而使用 load(file) 函數便可讀取數據。(其中 obj 是待寫入的對象,file 是文件對象。 dump()load() 函數都可以多次使用,會在原來的基礎上繼續讀寫,這樣可以存儲多個數據。)

比如說我們下面創建兩個實例 example1.pyexample2.py 並且嘗試在它們之間傳輸一個列表和一個數據。爲了增大難度,我們將列表變爲三維,混合了數據類型,並且將其中一部分改爲元組。

#example1.py
import pickle
f = open("abc.pickle", 'wb+')
ls = [[(23, 29), (22, 79)], 'hello', '35']
num = 3.1415926
pickle.dump(ls, f)
pickle.dump(num, f)
#example2.py
import pickle
f = open("abc.pickle", 'rb')
newls = pickle.load(f)
newnum = pickle.load(f)
print(newls)
print(newnum)

我們先運行 example1.py ,這個時候便會產生一個叫做 abc.pickle 的文件。文件名和後綴怎麼取名都可以。我們先嚐試用文本編輯器打開這個文件,便會顯示以下的內容。

]q(]q(KKqKKOqeXhelloqX35qe.G@	!MJ.

之前說過, pickle 輸出的數據是**二進制(流)**的格式,它不能夠被直接以文本形式打開。所以在剛剛兩個實例中,都要使用 wbrb 寫入、讀取文件。

現在我們打開 example2.py 並運行,可以看到控制檯成功輸出了 example1.py 程序中寫入的結果,甚至連列表和元組的類型都沒有改變:

[[(23, 29), (22, 79)], 'hello', '35']
3.1415926

pickle 模塊的神奇之處在於它可以讓你免去文件“I/O”中的轉換環節。讓你能夠更快地完成數據的存儲功能。當然, pickle.load() 函數的預設是 ASCII 編碼,所以假如讀取後中文出現了亂碼(應該會直接報錯),這時我們修改 encoding 參數就可以了。

pickle.load(f, encoding = 'gb2312')

4. dumps() 與 loads() - 不一樣的功能

在自動補全時,我發現 pickle 還有 dumps()loads() 這兩個函數。一開始我以爲它做的是將多個數據存入一個文件中(這個用多個 dump() 函數就可以實現),然而還是發現 Too Young 了。查閱了官方文檔之後,發現這兩個的作用與 dump() load() 不同。 dump() 是直接將生成好的二進制(流)保存到文件中,而 dumps() 是直接返回一個二進制(流)。(沒有寫入文件,而是可以賦給其他變量)

平時,我們可能並不會去使用這兩個函數。不過其實在之後的使用中,它們可以用於在數據模塊中存儲 python 數據類型。例如 Redis 的鍵值並不能支持全部的 python 類型,但是如果用 dumps() 將一個二進制流傳入,讀取的時候再用loads() 完整取出,就可以簡單地實現多種數據格式的存儲。如果感興趣的話可以看一下我的另外一個文檔:[python] redis 模塊

結語與其他文檔

學習了 pickle 的功能,我們可以猜想它的取名可能影射的是作者想要實現將數據“完整地放入”並“完整地取出”的功能,不過這也有可能是作者的一種情懷。看完 pickle 這個模塊之後,你是不是對 python 存儲數據有了更深的認識呢?當然如果大家想要更加深入地瞭解這一個模塊,在 12.1. pickle — Python object serialization 中也有安全提示、相關模塊、支持類型等更詳細的文檔。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章