On 12/6/2012 2:18 AM, Giuseppe Corbelli wrote:
On 06/12/2012 01:17, Jaedyn K. Draper wrote:
Hello everyone!

So I'm working on a little project in which I'm using Python as an embedded
scripting engine. So far I've not had much trouble with it using boost.python,
but there's something I'd like to do with it if it's possible.

Basically, Python can be used to extend my C++ classes by adding functions and
even data values to the class. I'd like to be able to have these persist in
the C++ side, so one python function can add data members to a class, and then
later the same instance passed to a different function will still have them.
The goal here being to write a generic core engine in C++, and let users
extend it in Python in any way they need without ever having to touch the C++.

So what I thought would work was that I would store a |boost::python::object|
in the C++ class as a value |self|, and when calling the python from the C++,
I'd send that python object through |boost::python::ptr()|, so that
modifications on the python side would persist back to the C++ class.
Unfortunately when I try this, I get the following error:

|TypeError: No to_python (by-value) converter found for C++ type:
boost::python::api::object|

Is there any way of passing an object directly to a python function like that,
or any other way I can go about this to achieve my desired result?

Please post some example code. Is it an option to aggregate a std::map<string, bpy::object*> into the C++ class? It would serve somehow like a "__dict__" on the C++ side.

Before I go into the explanation here, I'll say that your suggestion actually gave me what I wanted. Thanks!

Still, I'll explain what I wanted, since you asked. Who knows? Maybe there's an even better way to implement it, though this way is working fantastically and seamlessly.

Ok, here's some theoretical example code of what I *want* to happen. (Far simplified from the actual use case, but should be easier to understand this way.)

On the C++ side, I have a generic class that has some base information in it:

class MyObj
{
    int SomeInt;
    std::string SomeStr;
};

This class is exposed to Python using boost.python. (I won't post that code here since it's basic enough and is working fine for me.)

On the python side, I'd like to have, for example, two events that expect a MyObj as their first argument:

def OnFirstEvent(obj):
    obj.SomeList = [1, 2, 3, 4, 5]
    print obj.SomeList

def OnSecondEvent(obj):
    obj.SomeList += [6, 7, 8, 9, 10]
    print obj.SomeList

If, in the C++, I then call those like this:

void MyFunc()
{
    MyObj obj;
    globals["OnFirstEvent"](ptr(&obj));
    globals["OnSecondEvent"](ptr(&obj));
}

The first event will work fine, and print out [1, 2, 3, 4, 5] as expected.
When the second event is called, the information from the first event is lost, as it isn't part of the base C++ object so there's nothing on that object that stores it. So it throws an AttributeError.

My idea to fix that was to do this:

class MyObj
{
public:
    MyObj() : self(ptr(this)) {}
    boost::python::object *GetPyObj(){ return &PyObj; }
private:
    int SomeInt;
    std::string SomeStr;
    boost::python::object PyObj;
};

void MyFunc()
{
    MyObj obj;
    globals["OnFirstEvent"](ptr(obj.GetPyObj()));
    globals["OnSecondEvent"](ptr(obj.GetPyObj()));
}

My thinking was that by keeping the object instance within the class in this way, I'd be able to make the new SomeList value persist. But I can't call the function by passing an actual python object, only by passing a C++ object that's been extended, because it tries to convert that object to an object.

Using a std::map as a pseudo-__dict__ analog as you suggested - combined with overloading __getattr__ and __setattr__ to work with that map instead of the default __dict__ - worked perfectly for this! It's not exactly what I had in mind but really I think it's probably a better solution than having the class hold an object pointing to itself. This is a MUCH better solution than what I'd come up with previously, which was working the way I wanted it to, but was pretty hacky and implemented in the python rather than the C++, which I wanted to avoid if possible.

Thanks for the suggestion!
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to