簡體   English   中英

如何覆蓋pickle類中的dump / load方法 - 自定義pickle和unpickling - Python

[英]How to overwrite the dump/load methods in the pickle class - customizing pickling and unpickling - Python

到目前為止,我所做的是:

import pickle

class MyPickler(pickle.Pickler):
    def __init__(self, file, protocol=None):
        super(MyPickler, self).__init__(file, protocol)

class MyUnpickler(pickle.Unpickler):
    def __init__(self, file):
        super(MyUnpickler, self).__init__(file) 

在我的主要方法中,這主要是我所擁有的

#created object, then... 
pickledObject = 'testing.pickle'
with open(pickledObject,'wb') as f:
    pickle = MyPickler(f)
    pickle.dump(object) #object is the object I want to pickle, created before this

with open(pickledObject, 'r') as pickledFile:
    unpickle = MyUnpickler(pickledFile)
    object2 = unpickle.load()

但是,當調用super方法時,這會給我以下錯誤: TypeError: must be type, not classobj

如何只覆蓋兩種方法,加載和轉儲? pickle文件位於C:\\ Python27 / lib / pickle.py下

編輯 enum.py文件可以在這里找到: http ://dpaste.com/780897/

對象詳細信息:對象初始化如下:

object = CellSizeRelation(CellSizeRelation.Values.FIRST)

CellSizeRelation是一個使用Enumeration的類:

class CellSizeRelation(Option):
    Values = enum.Enum('FIRST',
                       'SECOND')

在我挑選對象之前,我這樣做:

print object.Values._values 
print object.value.enumtype 

產量

[EnumValue(<enum.Enum object at 0x02E80E50>, 0, 'FIRST'), EnumValue(<enum.Enum object at 0x02E80E50>, 1, 'SECOND')
<enum.Enum object at 0x02E80E50>

在我解開並打印出相同的東西之后,我得到了這個輸出

[EnumValue(<enum.Enum object at 0x02E80E50>, 0, 'FIRST'), EnumValue(<enum.Enum object at 0x02E80E50>, 1, 'SECOND')
<enum.Enum object at 0x02ECF750>

問題是第二個對象地址發生了變化; 第一次初始化時, enumtype_values具有相同的地址。 但是,在拆除后,它們會更改地址。 當我嘗試比較兩個enumValues時,這會破壞我的代碼。 如果你查看enumValue類,compare函數會嘗試這樣做:

try:
        assert self.enumtype == other.enumtype
        result = cmp(self.index, other.index)

由於地址更改,因此斷言功能失敗。 我現在以某種方式需要確保enumtype的地址在unpickled時不會改變。 我想只是從unpickled文件中獲取值'FIRST',找到它的索引,並使用以下命令重新初始化對象:

def load:
    object = CellSizeRelation(CellSizeRelation.Values[INDEX])
    return object

您希望自定義對象狀態被pickle和unpickled的方式,而不是自定義加載和卸載功能。

您將不得不研究__getstate__unpickling普通類實例章節 ,在您的情況下定義__getstate____setstate__方法應該足夠了。

在你的情況下發生的是,有一個帶有EnumValue實例的類級屬性,它們是常量。 但是在unpickling上,創建了新的EnumValue實例,它們不再連接到類級屬性。

EnumValue實例確實有一個index屬性可用於將其狀態捕獲為整數而不是EnumValue實例,我們可以在恢復實例時再次使用它來查找正確的常量:

 class CellSizeRelation(Option):
     # skipping your enum definition and __init__ here

     def __getstate__(self):
         # capture what is normally pickled
         state = self.__dict__.copy()
         # replace the `value` key (now an EnumValue instance), with it's index:
         state['value'] = state['value'].index
         # what we return here will be stored in the pickle
         return state

     def __setstate__(self, newstate):
         # re-create the EnumState instance based on the stored index
         newstate['value'] = self.Values[newstate['value']]
         # re-instate our __dict__ state from the pickled state
         self.__dict__.update(newstate)

所以,通常,如果沒有__getstate__則實例__dict__被腌制。 我們現在確實返回了__dict__的副本,但是我們為它的索引(一個簡單的整數)換掉了EnumValue實例。 在unpickling上,通常新的實例__dict__會使用我們在pickle上捕獲的unpickled __dict__更新,但是現在我們已經定義了__setstate__ ,我們可以再次將enum索引替換為正確的EnumValue

EnumValue取決於Enum “枚舉類型”對象之間的id標識。 這有一些優點和缺點。

主要優點是兩次調用Enum('A', 'B')定義了不同的枚舉類型。 所以:

osx = Enum('Jaguar', 'Tiger', 'Leopard')
bigcats = Enum('Jaguar', 'Tiger', 'Leopard')

如果您希望能夠將OS X 10.4與條帶化查殺機器區分開來,這可能很有用。

但這也意味着當泡菜bigcats osxbigcats ,它們不僅會彼此不同,它們也將與任何早期的osxbigcats 一旦你想到它,現在真的有這個。

所以,你的解決方案不能涉及任何類型的黑客泡菜; 它將不得不涉及黑客enum模塊。

你需要為Enum定義一個合理的__cmp__方法, Enum你有意義。 如果你可以放棄osx-than-bigcats的區別,那很容易。 如果你不能,你需要一些其他的方法(可能在enum定義中添加一個顯式標記名,或者一個可選但在其他方面隱式自動遞增的計數器?)來處理它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM