如何使我的SWIG扩展模块与Pickle一起使用?

ale*_*kuk 14 python swig pickle

我有一个Python的扩展模块,它使用SWIG作为包装器,我尝试用Pickle序列化它,我失败了=)

  1. 如果有人有可以腌制的SWIG扩展源,我很乐意看到它!
  2. 好像我应该__reduce_ex__在我的C++代码中实现方法.有没有人有例子__reduce_ex__有类似的Stackoverflow问题,但它省略了manager_constructor规范和实现.

ale*_*kuk 14

好像我找到了适用于我的simlple解决方案:

所以,假设我们有C使用SWIG生成的类,然后我们用它包装

class PickalableC(C, PickalableSWIG):

    def __init__(self, *args):
        self.args = args
        C.__init__(self)
Run Code Online (Sandbox Code Playgroud)

这里PickalableSWIG

class PickalableSWIG:

    def __setstate__(self, state):
        self.__init__(*state['args'])

    def __getstate__(self):
        return {'args': self.args}
Run Code Online (Sandbox Code Playgroud)

然后

pickle.loads(pickle.dumps(C()))
Run Code Online (Sandbox Code Playgroud)

失败了,但是

pickle.loads(pickle.dumps(PickalableC()))
Run Code Online (Sandbox Code Playgroud)

成功=)


Pau*_*ice 5

这里是一些其他方法。没有一个普遍接受的答案具有普遍适用性,但是如果您的班级满足一些(简单)要求,那么您可以通过实例化实例本身(而不是包装版本)来使用户的腌制更加容易。这些技术全部由LSST afw软件包使用

请注意,使用__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
}
}
Run Code Online (Sandbox Code Playgroud)

如果您可以使用默认构造函数创建对象,然后对其进行操作以恢复其以前的状态,请使用以下方法:

%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)
}
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您的班级可以对内存进行二进制数据的串行化处理(例如,您自己的磁盘格式的某些内存中表示形式):

%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)
}
Run Code Online (Sandbox Code Playgroud)

最后,如果您使用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)
Run Code Online (Sandbox Code Playgroud)