[Boost-users] Copy of a C++ object extended with Boost.Python

53 views
Skip to first unread message

4ian

unread,
Aug 24, 2009, 3:06:06 PM8/24/09
to boost...@lists.boost.org
I have a simple C++ object, exposed to python with Boost.python, like
this :

-------------------------------------------------
BOOST_PYTHON_MODULE(MyModule)
{
class_<MyObject>("MyObject")...
}
-------------------------------------------------

I call then python, making an instance of MyObject accessible :

-------------------------------------------------
MyObject anInstance;

object main_module((handle<>( borrowed( PyImport_AddModule
( "__main__" ) ) ) ) );
object main_namespace = main_module.attr( "__dict__" );
object myModule( (handle<>(PyImport_ImportModule("MyModule"))) );
main_namespace["anInstance"] = ptr(&anInstance);

try
{
handle<> ignored(( PyRun_String( "anInstance.aNewMember = 1;print
anInstance.aNewMember;",
Py_file_input,
main_namespace.ptr(),
main_namespace.ptr() ) ) );
}
catch ( error_already_set )
{
PyErr_Print();
}
-------------------------------------------------

You can observe that I've added a member ( aNewMember ) to MyObject
instance.
But if I make a copy of my object :

-------------------------------------------------
MyObject anotherInstance = anInstance;

main_namespace["anotherInstance"] = ptr(&anotherInstance);

try
{
handle<> ignored(( PyRun_String( "print
anotherInstance.aNewMember;",
Py_file_input,
main_namespace.ptr(),
main_namespace.ptr() ) ) );
}
catch ( error_already_set )
{
PyErr_Print();
}
-------------------------------------------------

I have a error saying that MyObject hasn't any "aNewMember" member.
What I have added with python has not been copied/transfered.
Is there a workaround to add permanently some new members to wrapped
objects ?
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

OvermindDL1

unread,
Aug 24, 2009, 4:01:06 PM8/24/09
to boost...@lists.boost.org

You are adding an entry to the __dict__ of the wrapper class that
contains the MyObject, but on the line MyObject anotherInstance =
anInstance; you are creating a copy of only the C++ object, not the
wrapper object that has the __dict__. You need to make a copy of it
through the Python bindings, not directly on the C++ copy-constructor
because then you are just copying the MyObject, not the wrapper
object.

I have worked around it by putting a dict in MyObject and exposing it
to python as __dict__ though, just make sure you overload your copy
constructor so you copy the dict too and not just make a copy of the
dict handle, that is important. I did this work-around in an odd way,
not sure it would work directly in Boost.Python, but I would think so.
I think the proper way in Boost.Python would be to (multi-)subclass
your MyObject from that one wrapper helper so you can get the python
self from your class's this, then you can copy the self (not the
handle, again this is important) to the new one as well.

4ian

unread,
Aug 25, 2009, 5:52:54 AM8/25/09
to boost...@lists.boost.org
Thanks for you response !
When you say "that one wrapper helper", are you speaking about the
object class of Boost.python, or about a home made class ?

On 24 août, 22:01, OvermindDL1 <overmind...@gmail.com> wrote:

> Boost-us...@lists.boost.orghttp://lists.boost.org/mailman/listinfo.cgi/boost-users

OvermindDL1

unread,
Aug 25, 2009, 3:55:42 PM8/25/09
to boost...@lists.boost.org
On Tue, Aug 25, 2009 at 3:52 AM, 4ian<dark...@gmail.com> wrote:
> Thanks for you response !
> When you say "that one wrapper helper", are you speaking about the
> object class of Boost.python, or about a home made class ?

Neither. I do not recall the name of it, but you can subclass your
class from it, then anytime your class has a python object containing
it then you can use some getself comand or something like that, it is
in the docs somewhere (but I am not in a good position to look at the
docs right now, maybe tonight if you have not found it yet).

4ian

unread,
Aug 27, 2009, 12:46:38 PM8/27/09
to boost...@lists.boost.org
I'm afraid I'm unable to find this class or anything that can help me
to copy the Python __dict__ associated with my C++ object...

On 25 août, 21:55, OvermindDL1 <overmind...@gmail.com> wrote:


> On Tue, Aug 25, 2009 at 3:52 AM, 4ian<dark4...@gmail.com> wrote:
> > Thanks for you response !
> > When you say "that one wrapper helper", are you speaking about the
> > object class of Boost.python, or about a home made class ?
>
> Neither.  I do not recall the name of it, but you can subclass your
> class from it, then anytime your class has a python object containing
> it then you can use some getself comand or something like that, it is
> in the docs somewhere (but I am not in a good position to look at the
> docs right now, maybe tonight if you have not found it yet).
> _______________________________________________
> Boost-users mailing list

> Boost-us...@lists.boost.orghttp://lists.boost.org/mailman/listinfo.cgi/boost-users

OvermindDL1

unread,
Aug 27, 2009, 6:19:58 PM8/27/09
to boost...@lists.boost.org
On Thu, Aug 27, 2009 at 10:46 AM, 4ian<dark...@gmail.com> wrote:
> I'm afraid I'm unable to find this class or anything that can help me
> to copy the Python __dict__ associated with my C++ object...
>
> On 25 août, 21:55, OvermindDL1 <overmind...@gmail.com> wrote:
>> On Tue, Aug 25, 2009 at 3:52 AM, 4ian<dark4...@gmail.com> wrote:
>> > Thanks for you response !
>> > When you say "that one wrapper helper", are you speaking about the
>> > object class of Boost.python, or about a home made class ?
>>
>> Neither.  I do not recall the name of it, but you can subclass your
>> class from it, then anytime your class has a python object containing
>> it then you can use some getself comand or something like that, it is
>> in the docs somewhere (but I am not in a good position to look at the
>> docs right now, maybe tonight if you have not found it yet).

Found it, it is in the FAQ, apparently the wrapper class I used was
one I made, but it talks about how to make it there, and an
alternate/better method if you are using shared_ptr:
http://beta.boost.org/doc/libs/1_40_0/libs/python/doc/v2/faq.html#xref

4ian

unread,
Aug 28, 2009, 10:20:30 AM8/28/09
to boost...@lists.boost.org
I have found a discussion called "Getting Python Object from C++
object" : http://osdir.com/ml/python.c++/2003-08/msg00191.html
It use shared_ptr and boost "enable_shared_from_this" template. Thanks
to this, we could "just write object(p) to get the Python object
back." like described in the FAQ.

I have modified the code so as to implement a function which copy the
dict of an object "A" to the dict of another object "A" ( implementing
this as operator= would be better, but it's just to test ).
I've added the objects A to a container of type C so as to create a
shared_ptr and make sure that self() will return a valid shared_ptr.
However, it didn't seems to work, it crash when i try to do a "object
(self())" so as to get the python object :

----------------------
#include <assert.h>
#include <iostream>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/python.hpp>

using namespace boost;
using namespace boost::python;

struct RuntimeError
{
RuntimeError( std::string msg ) : message( msg ) { }
const char *what() const throw() { return message.c_str(); }
std::string message;
};

void runtime_error( RuntimeError const &x )
{
PyErr_SetString( PyExc_RuntimeError, x.what() );
}

class A : public enable_shared_from_this<A>
{
public:
typedef shared_ptr<A> A_ptr;

/* Here 'a' tries to get the shared_ptr representing the
* python object from boost::python.
* Certainly this only works after a shared pointer has
* actually been created, e.g. by adding 'a' to a container
* of type C. After that, shared_from_this() actually returns
* a valid shared_ptr, which can be used for getting the
* respective python::object.
*/
virtual A_ptr self()
{
if ( _internal_weak_this.expired() )
throw RuntimeError( "Shared pointer not available." );
shared_ptr<A> self = shared_from_this();
assert( self != 0 );
return self;
}

//Very simple function to copy the dict of the python objects
void Copy( A & o )
{
object(self()).attr("__dict__") = object(o.self()).attr
("__dict__");
}

virtual ~A() {};
};

class C
{
private:
typedef A::A_ptr A_ptr;
public:
void set( A_ptr a ) { this->a = a; } // store instance
A_ptr get() { return this->a; }

private:
A_ptr a;
};

BOOST_PYTHON_MODULE( self_test )
{
register_exception_translator<RuntimeError>( &::runtime_error );

class_<A>( "A" ).def( "self", &A::self );
class_<C>( "C" ).def( "set", &C::set ).def( "get", &C::get );
}

int main()
{
PyImport_AppendInittab( "self_test", &initself_test );
Py_Initialize();

A a_cpp;
A a2_cpp;

object main_module(( handle<>( borrowed( PyImport_AddModule


( "__main__" ) ) ) ) );
object main_namespace = main_module.attr( "__dict__" );

object self_test(( handle<>( PyImport_ImportModule
( "self_test" ) ) ) );
main_namespace["self_test"] = self_test;
main_namespace["a"] = &a_cpp;
main_namespace["a2"] = &a2_cpp;

try
{
handle<> ignored(( PyRun_String( "c = self_test.C();c.set
(a);a.self();print a;a.member=42;",


Py_file_input,
main_namespace.ptr(),
main_namespace.ptr() ) ) );

handle<> ignored(( PyRun_String( "c2 = self_test.C();c2.set
(a2);a2.self();print a2;a2.othermember=23;",


Py_file_input,
main_namespace.ptr(),
main_namespace.ptr() ) ) );
}
catch ( error_already_set )
{
PyErr_Print();
}

a2_cpp.Copy(a_cpp); //Crash
}
----------------------

Theorically, the call to C::set would prevent the crash...

On 28 août, 00:19, OvermindDL1 <overmind...@gmail.com> wrote:

> Boost-us...@lists.boost.orghttp://lists.boost.org/mailman/listinfo.cgi/boost-users

Reply all
Reply to author
Forward
0 new messages