10.1 一切都依我想!
有時候,你的物件裡面可能會有很多不想透過網路傳遞的服務器物件,或者根本不能傳遞的東西,比如檔案、資料庫等等。
為了讓序列化也能在這種情況下運作,我們讓類別自己管理自己的序列化。這就是我們要用到一些特殊的method:__reduce__(), __getstate__(),__setstate__()。這些method 讓你能夠指定物件該如何被序列化和還原。
主要的控制序列化的方法:
-
__reduce__():指定物件該如何被序列化。 -
__getstate__():返回用於序列化的物件狀態。 -
__setstate__(self, state):從狀態中還原物件。
下面我會詳細說明它們,以及如何一起使用。
10.2 方法 __reduce__()
方法 __reduce__() 返回一個 tuple,指示物件該如何被序列化和反序列化。這個 tuple 通常包含:
- 用於還原物件的 function 或 class 的引用。
- 用於該 function 或 class 的 arguments 的 tuple。
- 物件的額外狀態(如果需要)。
範例:
import pickle
class CustomClass:
def __init__(self, value):
self.value = value
def __reduce__(self):
return (self.__class__, (self.value,))
def __repr__(self):
return f"CustomClass(value={self.value})"
# 創建物件
obj = CustomClass(42)
# 序列化物件
serialized_obj = pickle.dumps(obj)
print("序列化的物件:", serialized_obj)
# 反序列化物件
deserialized_obj = pickle.loads(serialized_obj)
print("反序列化的物件:", deserialized_obj)
預設情況下,function __reduce__() 的行為是這樣的:
class CustomClass:
def __init__(self, value):
self.value = value
def __reduce__(self):
# 定義類別
cls = self.__class__
# 建構子參數
args = (self.value,)
# 物件狀態
state = self.__dict__
return (cls, args, state)
它返回一個包含三個物件的 tuple:
當前類別的引用建構子參數(tuple)當前物件狀態的引用
如果你滿意這種行為,可以不必重新定義 __reduce__()。
10.3 讀取和寫入狀態
方法 __getstate__() 和 __setstate__()
這些方法用來在序列化和反序列化過程中管理物件的狀態。
-
__getstate__():返回需要序列化的物件狀態。 -
__setstate__(self, state):從狀態中還原物件。
範例:
假設我們不想保存物件的所有屬性,而想排除某些屬性。為此在 __getstate__() 方法中需要:
- 把當前物件的狀態(由服務性字段
__dict__定義)拷貝到一個單獨的變量——字典state。 - 刪除不需要序列化的所有屬性。
- 將獲得的物件作為
__getstate__()方法的結果返回。
import pickle
class CustomClass:
def __init__(self, value):
self.value = value
self.internal_state = "internal"
def __getstate__(self):
state = self.__dict__.copy()
del state['internal_state'] # 排除內部狀態
return state
def __setstate__(self, state):
self.__dict__.update(state)
self.internal_state = "restored internal" # 還原內部狀態
def __repr__(self):
return f"CustomClass(value={self.value}, internal_state={self.internal_state})"
# 創建物件
obj = CustomClass(42)
print("原始物件:", obj)
# 序列化物件
serialized_obj = pickle.dumps(obj)
print("序列化的物件:", serialized_obj)
# 反序列化物件
deserialized_obj = pickle.loads(serialized_obj)
print("反序列化的物件:", deserialized_obj)
在反序列化時,在 __setstate__() 方法中,我們做兩件事情:
- 使用
update()方法更新當前物件的狀態。 - 對於
internal_state等不需要序列化的屬性賦新值。
GO TO FULL VERSION