我有一个Python的扩展模块,它使用SWIG作为包装器,我尝试用Pickle序列化它,我失败=)
__reduce_ex__
方法。有没有人有__reduce_ex__
的例子? There is similar Stackoverflow question但它忽略了manager_constructor
规范和实施。答案 0 :(得分:14)
好像我找到了适合我的simlple解决方案:
所以我们假设我们使用SWIG生成了类C
,然后用
class PickalableC(C, PickalableSWIG):
def __init__(self, *args):
self.args = args
C.__init__(self)
其中PickalableSWIG
是
class PickalableSWIG:
def __setstate__(self, state):
self.__init__(*state['args'])
def __getstate__(self):
return {'args': self.args}
然后
pickle.loads(pickle.dumps(C()))
失败了,但是
pickle.loads(pickle.dumps(PickalableC()))
成功=)
答案 1 :(得分:5)
以下是一些其他方法。没有像accepted answer那样具有普遍适用性,但如果您的类符合某些(简单)要求,那么您可以通过使实例本身(非包装版本)可选择来使您的用户更容易进行酸洗。这些技术全部由LSST afw package使用。
请注意,使用__getstate__
/ __setstate__
对进行取消镜像时,__init__
方法将不被调用,这意味着除非您小心,你将拥有一个你无法做任何事情的对象(如果你继续获得NotImplementedError: Wrong number or type of arguments for overloaded function
,这是一种可能性)。这促使我们使用__reduce__
(或者您可以从__init__
致电__setstate__
)。
如果您是SWIG-ing类Foo
,它接受您可以从实例访问的构造函数参数(例如,通过访问器),请将以下内容添加到您的接口(.i
)文件中:
%extend Foo {
%pythoncode {
def __reduce__(self):
# Requires matching constructor: __init__(foo, bar)
args = self.getFoo(), self.getBar()
return self.__class__, args
}
}
如果您可以使用默认构造函数创建对象,然后对其进行操作以重新获得其以前的状态,请使用以下内容:
%extend Foo {
%pythoncode {
def __getstate__(self):
args = self.getFoo(), self.getBar()
return args
def __setstate__(self, state):
# Requires empty constructor: __init__()
self.__init__()
foo, bar = state
self.setFoo(foo)
self.setBar(bar)
}
}
或者,如果您的类可以对内存进行二进制数据的序列化(例如,您自己的磁盘格式的某些内存中表示):
%include "cdata.i"
%extend Foo {
%pythoncode {
def __reduce__(self):
s = Serializer()
self.serialize(s)
size = s.getLength()
data = cdata(s.getData(), size)
return unreduceFoo, (data, size)
}
}
%pythoncode {
def unreduceFoo(data, size):
s = Serializer(size)
memmove(s.getData(), data)
return Foo(s)
}
最后,如果您使用的是boost::serialization
,请使用Sogo Mineo的此代码段:
%{
#include <boost/serialization/serialization.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <sstream>
%}
%include "std_string.i"
%define %boost_picklable(cls...)
%extend cls {
std::string __getstate__()
{
std::stringstream ss;
boost::archive::binary_oarchive ar(ss);
ar << *($self);
return ss.str();
}
void __setstate_internal(std::string const& sState)
{
std::stringstream ss(sState);
boost::archive::binary_iarchive ar(ss);
ar >> *($self);
}
%pythoncode %{
def __setstate__(self, sState):
self.__init__()
self.__setstate_internal(sState)
%}
}
%enddef
%boost_picklable(Foo)
答案 2 :(得分:2)
我必须对接受的答案进行微小的更改才能使其适用于我的案例。由于我的类的初始化函数有一些输入参数,我不得不在*arg
函数中添加一个额外的参数C.__init(self)
,如下所示:
class PickalableC(C, PickalableSWIG):
def __init__(self, *args):
self.args = args
C.__init__(self, *args)
也许这对某人有帮助。我希望这不是太微不足道。
我发布了它作为答案,因为我无法发表评论,并且知道这不是你编辑帖子的内容。