Copying a boost.python object

北城以北 提交于 2019-12-10 07:37:05

问题


I have some boost python classes, which I instantiate in python. I want to copy them. So, if I have

p = Bernoulli(0.5)

I want to do

q = Bernoulli(p)

But what if I don't know p's type? I tried to do this:

q = copy.deepcopy(p)

but python said it couldn't pickle p.

Is my only solution to add a clone() function to the interface of Bernoulli? Or can I have that method automatically generated somehow? Can copy.deepcopy be made to work with Boost.python objects?


回答1:


From http://mail.python.org/pipermail/cplusplus-sig/2009-May/014505.html

#define PYTHON_ERROR(TYPE, REASON) \
{ \
    PyErr_SetString(TYPE, REASON); \
    throw bp::error_already_set(); \
}

template<class T>
inline PyObject * managingPyObject(T *p)
{
    return typename bp::manage_new_object::apply<T *>::type()(p);
}

template<class Copyable>
bp::object
generic__copy__(bp::object copyable)
{
    Copyable *newCopyable(new Copyable(bp::extract<const Copyable
&>(copyable)));
    bp::object
result(bp::detail::new_reference(managingPyObject(newCopyable)));

    bp::extract<bp::dict>(result.attr("__dict__"))().update(
        copyable.attr("__dict__"));

    return result;
}

template<class Copyable>
bp::object
generic__deepcopy__(bp::object copyable, bp::dict memo)
{
    bp::object copyMod = bp::import("copy");
    bp::object deepcopy = copyMod.attr("deepcopy");

    Copyable *newCopyable(new Copyable(bp::extract<const Copyable
&>(copyable)));
    bp::object
result(bp::detail::new_reference(managingPyObject(newCopyable)));

    // HACK: copyableId shall be the same as the result of id(copyable)
in Python -
    // please tell me that there is a better way! (and which ;-p)
    int copyableId = (int)(copyable.ptr());
    memo[copyableId] = result;

    bp::extract<bp::dict>(result.attr("__dict__"))().update(
        deepcopy(bp::extract<bp::dict>(copyable.attr("__dict__"))(),
memo));

    return result;
}

To use it:

class_<foo>(foo)
   .def("__copy__", &generic__copy__< foo >)
   .def("__deepcopy__", &generic__deepcopy__< foo >)
   .def(init< const foo & >())



回答2:


For copying, you can either implement the __copy__ and __deepcopy__ special methods (one of them could just wrap the copy constructor, depending on the C++ copy semantics of the class), or add pickling support. The copy module will use the special copying methods if they are available and the pickling methods otherwise.

Here is an example for using the copy constructor to implement __copy__:

template<typename T> const T copyObject(const T& v) { return v; }
boost::python::class_<C>("C").def("__copy__", copyObject<C>);



回答3:


Yes, you can make boost::python objects deep-copyable (and also pickable) by implementing the __setstate__ and __getstate__ methods on your object.

Basically, __getstate__ should return an (python) object that represents the internal state of your object, while __setstate__ obviously accepts said object and updates the state of your object.

If your object takes arguments for __init__, you should also look at implementing __getinitargs__.

See the Python docs for more information.



来源:https://stackoverflow.com/questions/4696966/copying-a-boost-python-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!