sometype.__new__ and C subclasses

James Porter porterj at alum.rit.edu
Sun May 2 16:03:45 EDT 2010


On 5/2/2010 1:43 PM, Robert Kern wrote:
> Perhaps things would be clearer if you could post the C code that you've
> written that fails. So far, you've only alluded at what you are doing
> using Python-syntax examples.

I'm not sure how much this will help, but here you go. The actual C code 
probably doesn't matter except for where I set tp_flags, tp_new, and 
register the type, but I included it for completeness. The full C source 
is available here if you need it, but be warned that other strangeness 
abounds in the code: 
<http://trac.mcs.anl.gov/projects/ITAPS/browser/python/trunk/iMesh_array.inl?rev=3831>.

Obviously, this is kind of a bizarre case, so I'm not entirely sure what 
the best route is here.

Thanks,
Jim

static PyObject*
iMeshArrObj_new(PyTypeObject *cls,PyObject *args,PyObject *kw)
{
     static char *kwlist[] = {"object","instance",0};

     PyObject *obj;
     iMesh_Object *instance = NULL;
     PyObject *arr = NULL;
     iMeshArr_Object *self;

     if(!PyArg_ParseTupleAndKeywords(args,kw,"O|O!",kwlist,&obj,
                                     &iMesh_Type,&instance))
         return NULL;

     arr = PyArray_FROM_O(obj);
     if(arr == NULL)
         return NULL;

     self = (iMeshArr_Object*)PyObject_CallMethod(arr,"view","O",cls);
     Py_DECREF(arr);
     if(self == NULL)
         return NULL;

     /* some boring stuff to set |instance| */

     return self;
}

static void
iMeshArrObj_dealloc(iMeshArr_Object *self)
{
     Py_XDECREF(self->instance);
     self->array.ob_type->tp_free((PyObject*)self);
}

static PyObject*
iMeshArrObj_finalize(iMeshArr_Object *self,PyObject *args)
{
     iMeshArr_Object *context;
     if(PyArg_ParseTuple(args,"O!",&iMeshArr_Type,&context))
     {
         self->instance = context->instance;
         Py_XINCREF(self->instance);
     }
     PyErr_Clear();
     Py_RETURN_NONE;
}

static PyMethodDef iMeshArrObj_methods[] = {
     { "__array_finalize__", (PyCFunction)iMeshArrObj_finalize,
       METH_VARARGS, ""
     },
     {0}
};

static PyMemberDef iMeshArrObj_members[] = {
     {"instance", T_OBJECT_EX, offsetof(iMeshArr_Object, instance),
      READONLY, "base iMesh instance"},
     {0}
};

static PyTypeObject iMeshArr_Type = {
     PyObject_HEAD_INIT(NULL)
     /* ... */
     (destructor)iMeshArrObj_dealloc,          /* tp_dealloc */
     /* ... */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
     "iMesh array objects",                    /* tp_doc */
     /* ... */
     iMeshArrObj_methods,                      /* tp_methods */
     iMeshArrObj_members,                      /* tp_members */
     /* ... */
     iMeshArrObj_new,                          /* tp_new */
};

PyMODINITFUNC initiMesh(void)
{
     PyObject *m;
     m = Py_InitModule("iMesh",module_methods);
     import_array();

     iMeshArr_Type.tp_base = &PyArray_Type;	
     if(PyType_Ready(&iMeshArr_Type) < 0)
         return;
     Py_INCREF(&iMeshArr_Type);
     PyModule_AddObject(m,"Array",(PyObject *)&iMeshArr_Type);
}

/***** End C code *****/

And then in Python:

     A = iMesh.Array(numpy.array([1,2,3,4,5]), instance=mesh)
     numpy.zeros_like(A) # fails here

Inside NumPy, zeros_like looks like this (there's a bit more than this, 
but it's irrelevant to this problem):

     def zeros_like(a):
         if isinstance(a, ndarray):
             res = ndarray.__new__(type(a), a.shape, a.dtype,
                                   order=a.flags.fnc)
             res.fill(0)
             return res




More information about the Python-list mailing list