复制一个boost.python对象

4 投票
3 回答
2910 浏览
提问于 2025-04-16 09:59

我有一些用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 & >())

撰写回答