2014-02-13 45 views
20

我一直在使用的泡菜,很開心,然後我看到這篇文章:Don't Pickle Your DataPython:爲什麼泡菜?

進一步閱讀它看起來像:

我已經切換到將數據保存爲JSON,但我想知道最佳實踐:

鑑於所有這些問題,您何時會使用泡菜?什麼樣的具體情況需要使用它?

+0

順便說一句,有一些格式比JSON更具可讀性,並且可以更容易地進行編輯。想起舊的INI文件和YAML。這當然比不透明的二進制流更好,但人的可讀性不是二元的。 – delnan

+0

我看到將對象保存爲JSON的第一個缺點:您必須創建序列化程序,這需要一些時間。再加上你的JSON過程的序列化速度,最終可能會比簡單的泡菜慢。雖然我同意安全缺點。還有一點是:你爲什麼要存儲一個對象並讓它可編輯?難道這不是不安全? – Depado

+2

爲什麼在使用螺絲刀時使用錘子?當你有錘子時,可以用螺絲刀嗎?這完全取決於爲手頭的工作選擇正確的工具。 –

回答

14

Pickle是不安全的,因爲它通過調用任意函數來構造任意的Python對象。但是,這也使得它能夠序列化幾乎任何Python對象,沒有任何樣板或甚至是白/黑名單(在一般情況下)。這對於某些使用情況非常有用:

  • 快速&簡單的序列化,例如用於暫停和恢復長時間運行但簡單的腳本。這裏沒有關注的問題,你只是想按照原樣轉儲程序狀態並稍後加載。
  • 將任意Python數據發送到其他進程或計算機,如multiprocessing。安全問題可能適用(但大多數不適用),一般性是絕對必要的,人類將不必閱讀它。

在其他情況下,沒有任何缺點是相當足以證明你的東西映射到JSON或其他限制性數據模型的工作。也許你不希望需要人類的可讀性/安全性/跨語言兼容性,或者你可能沒有。請記住,你不會需要它。使用JSON將是正確的事情,但正確並不總是好事。

你會注意到我完全忽略了「慢」的缺點。這是因爲它的部分誤導:Pickle的數據確實比較適合JSON模型(字符串,數字,數組,地圖)的數據,但如果您的數據是這樣的話,那麼您應該使用JSON出於其他原因。如果您的數據不是這樣(很有可能),您還需要考慮將對象轉換爲JSON數據所需的自定義代碼,以及將JSON數據轉換回您的自定義代碼對象。它增加了工程成本和運行時間開銷,必須根據具體情況對其進行量化。

+0

感謝您的一個很好的答案。很高興知道什麼是正確的事情,即使它不總是==好 – emh

+0

在'multiprocessing'中,也是火花。在使用RDD時,spark會序列化用戶定義的函數(傳遞給map,flatmap)[使用pickle](https://spark.apache.org/docs/1.1.1/api/python/pyspark.serializers.PickleSerializer- class.html),因爲它可以序列化幾乎所有的python對象。 –

3

Pickle具有便利的優勢 - 它可以序列化任意對象圖,而不需要額外的工作,並且可以處理相當廣泛的Python類型。這就是說,在新代碼中使用Pickle是不尋常的。 JSON只是更清潔的工作。

1

你可以在JSON vs. Pickle security找到一些答案:JSON只能使用unicode,int,float,NoneType,bool,list和dict。如果你想醃製更高級的對象,比如類實例,你就不能使用它。請注意,對於這些泡菜,沒有希望成爲語言不可知論者。

同時使用cPickle代替Pickle部分解決了速度的進步。

+0

雖然cPickle也更快,然後我看到:http://stackoverflow.com/questions/16833124/pickle-faster-than-cpickle-with-numeric-data – emh

2

我通常既不使用Pickle也不使用JSON,但是它既安全又快速,並生成小尺寸的串行數據。

另一個優點是可以與用其他語言編寫的軟件交換數據(當然在JSON的情況下也是如此)。

+0

JSON最大的優點恕我直言,它既簡潔(不像XML),也可讀可讀(與MessagePack不同)。我不確定MessagePack節省的大小是否足以否定這兩個好處。 – CadentOrange

+0

它不像MessagePack中的大小節省那麼多,但是你可以編碼JSON不太好的東西,比如二進制數據。 – Joe

+0

MessagePack無法序列化'set',多麼可恥 –

0

我已經嘗試了幾種方法,並發現使用cPickle將dump方法的協議參數設置爲:cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)是最快的轉儲方法。

import msgpack 
import json 
import pickle 
import timeit 
import cPickle 
import numpy as np 

num_tests = 10 

obj = np.random.normal(0.5, 1, [240, 320, 3]) 

command = 'pickle.dumps(obj)' 
setup = 'from __main__ import pickle, obj' 
result = timeit.timeit(command, setup=setup, number=num_tests) 
print("pickle: %f seconds" % result) 

command = 'cPickle.dumps(obj)' 
setup = 'from __main__ import cPickle, obj' 
result = timeit.timeit(command, setup=setup, number=num_tests) 
print("cPickle: %f seconds" % result) 


command = 'cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)' 
setup = 'from __main__ import cPickle, obj' 
result = timeit.timeit(command, setup=setup, number=num_tests) 
print("cPickle highest: %f seconds" % result) 

command = 'json.dumps(obj.tolist())' 
setup = 'from __main__ import json, obj' 
result = timeit.timeit(command, setup=setup, number=num_tests) 
print("json: %f seconds" % result) 


command = 'msgpack.packb(obj.tolist())' 
setup = 'from __main__ import msgpack, obj' 
result = timeit.timeit(command, setup=setup, number=num_tests) 
print("msgpack: %f seconds" % result) 

輸出:

pickle   : 0.847938 seconds 
cPickle  : 0.810384 seconds 
cPickle highest: 0.004283 seconds 
json   : 1.769215 seconds 
msgpack  : 0.270886 seconds 

所以,我更喜歡的cPickle在需要實時性能,如從攝像機的視頻流傳輸到 服務器的情況下最高傾銷協議。