[C++-sig] how to deep copy boost python object

Matthew Scouten (TT) Matthew.Scouten at tradingtechnologies.com
Mon May 11 18:31:41 CEST 2009


If you make an object pickleable, you get deepcopy for free, because the
deepcopy function will use a pickle-unpickle cycle as a fall back if it
cannot find any other way to copy. This has the disadvantage that you
must come up with a sensible pickled representation, and you pay for a
round trip through a string. This is especially annoying since all c++
objects are already deepcopyable by default: just use a call copy-ctor.

There is another way to tell python how to deepcopy an object: give it a
__deepcopy__ function (and a __copy__ function). 
This is some code I got from Hans Meine a while back:

#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 & >())


This has the advantage that you can use it on any existing class that
has a sensible cctor. 









-----Original Message-----
From:
cplusplus-sig-bounces+matthew.scouten=tradingtechnologies.com at python.org
[mailto:cplusplus-sig-bounces+matthew.scouten=tradingtechnologies.com at py
thon.org] On Behalf Of Gennadiy Rozental
Sent: Monday, May 11, 2009 12:47 AM
To: cplusplus-sig at python.org
Subject: Re: [C++-sig] how to deep copy boost python object

Ralf W. Grosse-Kunstleve <rwgk <at> yahoo.com> writes:

> 
> 
> A comprehensive approach is to make the object picklable.
> As a side-effect, copy.deepcopy() will also work.

1. Are you saying that copy.deepcopy does not work without object being
picklable? What will happend if I try to use it for non picklable
object?

2. What if object IS picklable. How will invoke deepcopy operation on
bp::object?

Gennadiy

_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig at python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


More information about the Cplusplus-sig mailing list