问题
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