序列化Python對象

序列化數據最常見的做法就是使用pickle模塊,要將某個對象轉儲到文件中,可以這樣做:

import pickle

def serailize_object():
data = [1, 2, 3]
f = open(somefile, wb)
pickle.dump(data, f)

要將對象轉儲為字元串,我們可以使用pickle.dumps():

s = pickle.dumps(data)

如果我們要從位元組流重新創建出對象,我們可以使用pickle.load()或者pickle.loads()函數。

# Restore from a file
f = open(somefile, rb)
data = pickle.load(f)

對於大部分程序來說,只要掌握dump()和load()函數的用法就可以高效地利用pickle模塊了。pickle是一種Python專有的自描述式的數據編碼,並且因為序列化的數據中包含有每個對象的開始和結束以及有關對象類型的信息,因此,我們不必單行應該如何定義記錄,pickle就能完成了。

# Restore from a string
data = pickle.loads(s)

f = open(somedata, wb)
pickle.dump([1, 2, 3, 4], f)
pickle.dump(hello, f)
pickle.dump({Apple, Pear, Banana}, f)
f.close()

f = open(somedata, rb)
print(pickle.load(f))
print(pickle.load(f))
print(pickle.load(f))

if __name__ == __main__:
serailize_object()

注意:千萬不要對不信任的數據使用pickle.load()。 pickle在載入時有一個副作用就是它會自動載入相應模塊並構造實例對象。 但是某個壞人如果知道pickle的工作原理, 他就可以創建一個惡意的數據導致Python執行隨意指定的系統命令。 因此,一定要保證pickle只在相互之間可以認證對方的解析器的內部使用。

有些類型的對象是不能被序列化的。這些通常是那些依賴外部系統狀態的對象, 比如打開的文件,網路連接,線程,進程,棧幀等等。 用戶自定義類可以通過提供 __getstate__()__setstate__()方法來繞過這些限制。 如果定義了這兩個方法,pickle.dump() 就會調用 __getstate__() 獲取序列化的對象。 類似的,__setstate__() 在反序列化時被調用。為了演示這個工作原理, 下面是一個在內部定義了一個線程但仍然可以序列化和反序列化的類:

# countdown.py
import time
import threading

class Countdown:
def __init__(self, n):
self.n = n
self.thr = threading.Thread(target=self.run)
self.thr.daemon = True
self.thr.start()

def run(self):
while self.n > 0:
print(T-minus, self.n)
self.n -= 1
time.sleep(5)

def __getstate__(self):
return self.n

def __setstate__(self, n):
self.__init__(n)

試著運行下面的序列化試驗代碼:

>>> import countdown
>>> c = countdown.Countdown(30)
>>> T-minus 30 T-minus 29 T-minus 28
...
>>> # After a few moments
>>> f = open(cstate.p, wb)
>>> import pickle
>>> pickle.dump(c, f)
>>> f.close()

然後退出Python解析器並重啟後再試驗下:

>>> f = open(cstate.p, rb)
>>> pickle.load(f) countdown.Countdown object at 0x10069e2d0> T-minus 19 T-minus 18
...

你可以看到線程又奇蹟般的重生了,從你第一次序列化它的地方又恢復過來。

pickle 對於大型的數據結構比如使用 arraynumpy 模塊創建的二進位數組效率並不是一個高效的編碼方式。 如果你需要移動大量的數組數據,你最好是先在一個文件中將其保存為數組數據塊或使用更高級的標準編碼方式如HDF5 (需要第三方庫的支持)。

由於 pickle 是Python特有的並且附著在源碼上,所有如果需要長期存儲數據的時候不應該選用它。 例如,如果源碼變動了,你所有的存儲數據可能會被破壞並且變得不可讀取。 坦白來講,對於在資料庫和存檔文件中存儲數據時,你最好使用更加標準的數據編碼格式如XML,CSV或JSON。 這些編碼格式更標準,可以被不同的語言支持,並且也能很好的適應源碼變更。

最後一點要注意的是 pickle 有大量的配置選項和一些棘手的問題。 對於最常見的使用場景,你不需要去擔心這個,但是如果你要在一個重要的程序中使用pickle去做序列化的話, 最好去查閱一下

pickle - Python object serialization - Python 3.7.2 documentation?

docs.python.org

參考書目

《Python CookBook》作者:【美】 David Beazley, Brian K. Jones

Github地址:

yidao620c/python3-cookbook?

github.com圖標
推薦閱讀:

相關文章