|
From: Murali D. <don...@ya...> - 2010-10-31 23:59:07
|
Thank you, Barry! I will modify my code as you suggest.
>> Python may try to delete this instance and that may fail.
fwiw,
I did some testing by having my python code assign the result of this method to
a variable and then set the variable to None.
At first it wasn't calling the destructor of my new style class. I printed out
reference counts of various objects in python and I noticed that these objects
created in C++ code had reference counts one higher than other objects. That is
when I added the "owned" argument to self() so that I could get an object with
the right reference count. After that, my destructors were being called and I
had no problems. I take that to mean Python is deleting the instance
successfully. Of course there could be other things wrong that I haven't tested,
and it is possible I have been lucky not to run into problems.
Murali
________________________________
From: Barry Scott <ba...@ba...>
To: Murali Donthireddy <don...@ya...>
Cc: PyCXX and improvement <cxx...@li...>
Sent: Sun, October 31, 2010 6:23:32 AM
Subject: Re: PyCXX and new style classes
On 29 Oct 2010, at 00:24, Murali Donthireddy wrote:
Barry,
>
>Thanks for the reply.
>
>BTW, I am using Python2 parts of version 2.6.1 of PyCXX.
>
>I used simple.cxx as my starting point. But all of the methods in
>"new_style_class" return Py::None. How do I create and return an instance of
>new_style_class to the python code? (In my application, I have more than one
>class, and a method of one class needs to return an instance of another class.)
>
>With some help from someone who knows c++ better than me, I managed to do what I
>needed and it seems to work. But it felt like a herculean effort.
>
It would do. You cannot do this from C++ on its own.
You have to create instances of your new style class using python calls.
Python does a lot of house keeping for new style classes that using raw C++
will bypass and lead to who knows what problems.
In pure python you would do this:
class new_style_class:
def __init__( self ):
...
instance = new_style_class()
"new_style_class" is in fact a type. You can call the type to create instances
of that type.
In PyCXX the type is available as new_style_class::type().
In simple.cxx you can see that being exposed as the "new_style_class" in the
module dictionary.
To create an instance in C++ you need code like this:
Py::Callable class_type( new_style_class::type() );
Py::PythonClassObject<new_style_class> new_style_obj( class_type.apply(
args, kwds ) );
I have updated the simple.cxx to include a new function (make_instance) that
shows this.
https://cxx.svn.sourceforge.net/svnroot/cxx/trunk/CXX/Demo/Python2/simple.cxx
>I added a second constructor to PythonClass and modified its self() to take an
>optional "owned" flag. I give all the code further down.
>
I think this will lead to problems.
>Let us call my subclasses of PythonClass A and B, they each wrap a pre-existing
>C++ class and hold a shared pointer to instances of those wrapped classes. Let
>us call the pointers a and b.
>
>I am now able to return a PythonClassInstance of B from a method A as
follows:
> const WrappedClass* x = < something that returns an instance of
>WrappedClass>;
> return (new B(x))->self(true);
>
Python may try to delete this instance and that may fail.
>I must be being monumentally stupid because there is a vast gap between what I
>had to do and your comment "simple.cxx is all you need". I don't see how that
>can be the case when simple.cxx doesn't have a single method that returns
>anything, let alone instances of user defined classes.
>
>Regardless of whether I did more than what was necessary, my extension works
>beautifully. I think PyCXX is a very nice tool. The fact that I could make
>changes to it is an indication of how well written it is. I am grateful for your
>work on PyCXX.
>
>thanks,
>Murali
>
>My changes to PythonClass, in header file CXX/Python2/ExtensionType.hxx:
>
> template<TEMPLATE_TYPENAME T> class PythonClass
> : public PythonExtensionBase
> {
> protected:
>[...]
> static PythonClassInstance* alloc_empty() {
> PyObject *py_optlib_expr = extension_object_new(type_object(),
>Tuple().ptr(), Dict().ptr());
> return reinterpret_cast<PythonClassInstance*>(py_optlib_expr);
> }
>
> PythonClass()
> : PythonExtensionBase()
> , m_class_instance( alloc_empty() )
> {
> reinterpret_cast< Py::PythonClassInstance *
>>(selfPtr())->m_pycxx_object =
> static_cast<PythonExtensionBase*>(this);
> }
>public:
> static const T* obj_from_arg(Object arg) {
> PythonClassInstance * b = reinterpret_cast<PythonClassInstance *>
>(arg.ptr());
> const T *val = static_cast<T *>(b->m_pycxx_object);
>
Any time you see reinterpret_cast in C++ is often a good sign that the code has
a problem.
(Deep library code will need to do this).
Here is a type safe way to do what you want (take from func() in simple.cxx):
Py::PythonClassObject<new_style_class> x2( x );
std::cout << "C++ pointer " << x2.getCxxObject() << std::endl;
return val;
> }
>
> virtual Object self(bool owned = false) // customization: Add optional
>argument owned.
> {
> return Object( reinterpret_cast<PyObject *>( m_class_instance
>), owned );
> }
>
Because python did not create the class for you you do not have a "self" that is
sane.
Given the changes you'll make to get python to create your objects this is not
needed.
Barry
|