这里有一些额外的方法。没有一个像accepted answer 那样具有普遍适用性,但是如果您的类满足一些(简单)要求,那么您可以通过使实例本身(未包装的版本)可腌制来使您的用户更容易腌制。这些技术都被LSST afw package使用了。
请注意,当使用 __getstate__/__setstate__ 对取消腌制时,__init__ 方法将不会被调用,这意味着除非你小心,否则你将拥有一个对象你无能为力(如果你不断收到NotImplementedError: Wrong number or type of arguments for overloaded function,这是一种可能性)。这促使我们使用__reduce__(或者您可以从__setstate__ 调用__init__)。
如果您正在 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 的这个sn-p:
%{
#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)