复制一个boost.python对象
我有一些用Boost.Python写的类,我在Python里创建了这些类的实例。现在我想复制它们。如果我有
p = Bernoulli(0.5)
我想这样做
q = Bernoulli(p)
但是如果我不知道p的类型呢?我试着这样做:
q = copy.deepcopy(p)
但是Python说它无法处理p的复制。
我唯一的解决办法是给Bernoulli这个类添加一个clone()函数吗?还是说我可以用某种方式自动生成这个方法?copy.deepcopy能否与Boost.Python对象一起使用?
3 个回答
1
是的,你可以让boost::python对象支持深拷贝(也就是可以完整复制)和序列化(也就是可以保存到文件或网络上)的方法,就是在你的对象里实现 __setstate__
和 __getstate__
这两个方法。
简单来说,__getstate__
这个方法应该返回一个(python)对象,这个对象代表了你自己对象的内部状态,而 __setstate__
则是用来接收这个状态对象,并更新你自己对象的状态。
如果你的对象在 __init__
方法中需要一些参数,你还应该考虑实现 __getinitargs__
方法。
想了解更多信息,可以查看Python的文档。
2
在复制对象的时候,你可以选择实现两个特别的方法:__copy__
和 __deepcopy__
。其中一个方法可以简单地调用复制构造函数,这取决于你用的C++类的复制规则。另外,你也可以添加序列化支持。如果这些特别的复制方法可用,copy
模块会使用它们;如果不可用,它就会使用序列化的方法。
下面是一个使用复制构造函数来实现__copy__
的方法示例:
template<typename T> const T copyObject(const T& v) { return v; }
boost::python::class_<C>("C").def("__copy__", copyObject<C>);
4
来自 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;
}
使用方法:
class_<foo>(foo)
.def("__copy__", &generic__copy__< foo >)
.def("__deepcopy__", &generic__deepcopy__< foo >)
.def(init< const foo & >())