[C++-sig] Re: PyObject * self member in class wrappers.
Dirk Gerrits
dirk at gerrits.homeip.net
Thu Jan 9 20:29:43 CET 2003
David Sankel wrote:
> When a python class is being inherited from a c++
> class, one must write a c++ wrapper around the c++
> class.
>
> This wrapper must have a pointer to a PyObject called
> self.
>
> I was wondering, what exactly is this PyObject?
Python provides a 'Python/C API' that allows you to create C/C++
extension modules and to embed the Python interpreter in your C/C++
programs. Pointers to PyObjects are the Python/C API's way to use Python
objects from the C/C++ side.
Boost.Python uses advanced C++ techniques to provide a much easier
interface to the Python/C API. One manifestation of this is in
python::object which is basically a (very) convenient, high-level
wrapper around PyObject*. A lower level wrapping around PyObject* is
python::handle.
> Say I have the following scenario:
>
> class Cloneable
> {
> public:
> virtual Cloneable * Clone()=0;
> };
>
> class PythonCloneable
> {
> public:
> PyObject * self;
> PythonCloneable( PyObject * self_ ) : self(self_) {}
>
> Cloneable * Clone()
> {
> PythonCloneable * theCopy;
> //... What goes here?
> return theCopy;
> }
> };
>
> I would like Clone to return a copy (not instance) of
> the original. This way, both the clone and the
> original could be modified independently. How would I
> manipulate the self member to do this?
Well I'm afraid that I'm not too sure myself. Here's what I thought up:
You can wrap a PyObject* in a python::handle<>, create a python::object
out of it and then copy that. Calling the copy's ptr() method gives you
it's PyObject*.
I'm just not totally sure whether you should construct the
python::handle from self or from python::borrowed(self). I think it is
the latter, resulting in:
Cloneable * Clone()
{
object theObject( handle(borrowed(self)) );
object theCopy(theObject);
return new PythonClonable(theCopy.ptr());
}
The problem with this however, is that theCopy falls out of scope at the
end of the function body so the clone will have a dangling self pointer.
Very bad!
To fix this, I think you could do this:
class PythonCloneable
{
object self_object;
public:
PyObject* self;
PythonCloneable( PyObject * self_ ) : self(self_) {}
PythonCloneable( handle<> self_ ) : self_object(self_)
{ self = self_object.ptr(); }
Cloneable* Clone()
{
object theObject( handle(borrowed(self)) );
object theCopy(theObject);
return new PythonClonable(theCopy);
}
};
I believe that should work. But I have not tested this. And it rather
feels like a hack.
I can't help but think that Boost.Python should provide a better way to
do this. If it is there, then I just didn't think of it. If not, then I
think it should be added, whatever 'it' may be.
Regards,
Dirk Gerrits
More information about the Cplusplus-sig
mailing list