8

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

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 是一个使用枚举的类:

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具有相同的地址。但是,在 unpickling 之后,它们会更改地址。当我尝试比较两个枚举值时,这会破坏我的代码。如果你查看enumValue类,比较函数会尝试这样做:

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

由于地址改变,assert 函数失败。我现在需要以某种方式确保枚举类型的地址在未腌制时不会改变。我正在考虑简单地从未腌制的文件中获取值“FIRST”,找出它的索引,然后使用以下命令重新初始化对象:

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

2 回答 2

11

您想要自定义对象状态的腌制和解封方式,而不是自定义加载和卸载功能。

您必须学习Pickling and unpickling normal class instances 一章,在您的情况下定义一个__getstate__and__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__被腌制。我们现在确实返回了 that 的副本__dict__,但是我们将EnumValue实例换成了它的索引(一个简单的整数)。在 unpickling 时,通常会使用我们在 pickling 中捕获__dict__的 unpickled 更新新实例__dict__,但是现在我们已经__setstate__定义了,我们可以将枚举索引换回正确的位置EnumValue

于 2012-08-03T19:45:03.480 回答
0

EnumValue取决于“枚举类型”对象id之间的身份。Enum这有一些优点和缺点。

主要优点是两次调用Enum('A', 'B')定义了不同的枚举类型。所以:

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

如果您希望能够将 OS X 10.4 与条纹杀戮机器区分开来,这可能很有用。

但这也意味着当 pickle unpickles osxand时bigcats,它们不仅会彼此不同,而且还会与osxand的任何早期实例不同bigcats。一旦你想到它,现在真的有任何东西。

因此,您的解决方案不能涉及任何类型的黑客泡菜;这将不得不涉及破解enum模块。

您将需要定义一个合理的__cmp__方法Enum来做对您有意义的事情。如果您可以放弃 osx-vs.-bigcats 的区别,那很容易。如果你不能,你需要一些其他的方式来enum处理它(也许在定义中添加一个显式的标签名称,或者一个可选但其他隐式自动增量计数器?)。

于 2012-08-03T19:44:30.077 回答