到目前为止,我所做的就是:
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
类,比较函数会尝试这样做:
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
答案 0 :(得分:7)
您希望自定义对象状态被pickle和unpickled的方式,而不是自定义加载和卸载功能。
您必须研究Pickling and unpickling normal class instances chapter,在您的情况下,定义__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上捕获的未标记__dict__
进行更新,但现在我们已经定义了__setstate__
,我们可以将枚举索引换出来再次正确EnumValue
。
答案 1 :(得分:0)
EnumValue
取决于id
“枚举类型”对象之间的Enum
标识。这有一些优点和缺点。
主要优点是对Enum('A', 'B')
的两次调用定义了不同的枚举类型。所以:
osx = Enum('Jaguar', 'Tiger', 'Leopard')
bigcats = Enum('Jaguar', 'Tiger', 'Leopard')
如果您希望能够将OS X 10.4与条纹查杀机区分开来,这可能很有用。
但这也意味着当pickle unpickles osx
和bigcats
时,它们不仅会彼此不同,它们也将与{}的任何早期实例区别开来。 {1}}和osx
。一旦你想到它,现在真的有了。
所以,你的解决方案不能涉及任何类型的黑客泡菜;它将不得不涉及黑客攻击bigcats
模块。
您需要为enum
定义合理的__cmp__
方法,以便对您有所帮助。如果你可以放弃osx-than-bigcats的区别,那很容易。如果你不能,你还需要一些其他的方法(可能会在Enum
定义中添加一个显式标记名,或者是一个可选但在其他方面隐式自动递增计数器?)来处理它。