From: Barry S. <ba...@ba...> - 2010-10-31 10:23:42
|
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 |