|
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
|