On 29 Oct 2010, at 00:24, Murali Donthireddy wrote:


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.


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.


My changes to PythonClass, in header file CXX/Python2/ExtensionType.hxx:

    template<TEMPLATE_TYPENAME T> class PythonClass
    : public PythonExtensionBase
        static PythonClassInstance* alloc_empty() {
            PyObject *py_optlib_expr = extension_object_new(type_object(), Tuple().ptr(), Dict().ptr());
            return reinterpret_cast<PythonClassInstance*>(py_optlib_expr);

            : PythonExtensionBase()
            , m_class_instance( alloc_empty() )
            reinterpret_cast< Py::PythonClassInstance * >(selfPtr())->m_pycxx_object = 
        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.