Re: [C++-sig] shared_ptr and register_ptr_to_python

2010-10-11 Thread Marek Denis

On 11.10.2010 00:42, Jim Bosch wrote:


Essentially, what you need to do is pass a Python object to call_method
(boost::python::object or PyObject *) that already contains your C++
object. In order to get one, you need need to tell Boost.Python to
construct A and B with what it calls a "back reference". Your C++
constructors will be given a PyObject* by boost.python, pointing to the
Python objects the C++ object will be wrapped in, and you can then store
those as data members and pass the PyObject * to call_method. You can
find more information in the Boost.Python reference docs on class_,
especially the "HeldType Semantics" section.


I did checked the docs, but I think I don't get how should it be done in 
my case. What they talk about (as well as in the provided example)
They let the user to create Python classes derived from C++ classes and 
launchind virtual Python function. Would ou mind providing a sample 
piece of code how should it be done to wrap my C++ object into PyObject* 
? Thanks in advance.



By the way, the call policies on your "gen" function should be
return_value_policy, not return_internal_reference<>;
the latter is for returning data members of wrapped classes and other
things that are owned by another existing wrapped object.


Good point, thanks!


--
regards

Marek Denis

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] shared_ptr and register_ptr_to_python

2010-10-11 Thread Jim Bosch

On 10/11/2010 10:49 AM, Marek Denis wrote:

On 11.10.2010 00:42, Jim Bosch wrote:


Essentially, what you need to do is pass a Python object to call_method
(boost::python::object or PyObject *) that already contains your C++
object. In order to get one, you need need to tell Boost.Python to
construct A and B with what it calls a "back reference". Your C++
constructors will be given a PyObject* by boost.python, pointing to the
Python objects the C++ object will be wrapped in, and you can then store
those as data members and pass the PyObject * to call_method. You can
find more information in the Boost.Python reference docs on class_,
especially the "HeldType Semantics" section.


I did checked the docs, but I think I don't get how should it be done in
my case. What they talk about (as well as in the provided example)
They let the user to create Python classes derived from C++ classes and
launchind virtual Python function. Would ou mind providing a sample
piece of code how should it be done to wrap my C++ object into PyObject*
? Thanks in advance.




I think this is something like what you want to do:

-

namespace bp = boost::python

class A {
public:

std::string getData() { return _data; }

void setCallback(bp::object const & callback) {
_callback = callback;
}

bp::object invokeCallback() {
 return _callback(getSelf());
}

virtual PyObject * getSelf() const = 0;

virtual ~A() {}

explicit A(std::string const & data) : _data(data) {}

private:
std::string _data;
bp::object _callback;
};

class B : public A {
public:
explicit B(std::string const & data) : A(data) {}
};

class PyA : public A {
public:

PyA(PyObject * self, std::string const & data) :
A(data), _self(self) {}

virtual PyObject * getSelf() const { return _self; }

private:
PyObject * _self;
};

class PyB : public B {
public:

PyB(PyObject * self, std::string const & data) :
B(data), _self(self) {}

virtual PyObject * getSelf() const { return _self; }

private:
PyObject * _self;
};

BOOST_PYTHON_MODULE(example) {
bp::class_("A", bp::init(bp::arg("data")))
.add_property("data", &A::getData)
.def("setCallback", &A::setCallback)
.def("invokeCallback", &A::invokeCallback)
bp::class_,PyB>(
"B",
 bp::init(bp::arg("data"))
);
}

-

A couple of notes:

- I have not tested this.  Likely there are some typos, and possibly 
even a bit of forgotten syntax - hopefully it's easy to correct.


- Note that there's no need to re-wrap the methods that B inherits from 
A, but you do have create both PyA and PyB if you want both A and B to 
be instantiable from Python (after all, getSelf() is pure virtual).


- If you have a C++ function that returns an A or B instance by 
reference or pointer, this code will still work.  Of course, such an 
object will have to find some other way to implement getSelf() - only 
objects instantiated in Python will actually be PyA or PyB instances.


- I didn't actually use call_method anywhere, because bp::object has an 
overloaded operator() that does what you need (and using object here is 
better than PyObject because it handles the reference counting; you 
don't use it for _self because we don't want reference counting there).


- This is a little non-standard because the base classes A and B are 
Python-aware and are pure virtual - but that makes sense, because your 
pattern requires that all C++ objects have a back-reference to their 
Python selves.


- I think there's a way to do this that merges each class with it's 
Python counterpart (i.e., it tells Boost.Python that A has a constructor 
that takes the special "self" argument), and it has something to do with 
specializing a template traits class.  But I haven't ever done it, and I 
don't want to lead you astray.



HTH!

Jim
___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig