[Numpy-discussion] Multiple inheritance from ndarray
Travis Oliphant
oliphant.travis at ieee.org
Tue Mar 21 10:03:05 CST 2006
Robert Lupton wrote:
> I've finally found time to return to this problem. Travis's made the
> suggestion that I could use code along the lines of:
>
>> class Image(ndarray, actImage):
>> def __new__(subtype, *args)
>> act1 = actImage.__new__(actImage, *args)
>> actImage.__init__(act1, *args)
>> arr = array(act1.getArray(), 'd', copy=False)
>> self = arr.view(subtype)
>>
>> return self
>
> and this makes sense. Unfortunately, the arr.view(subtype) fails:
> TypeError: Cannot change descriptor for objectarray.
> [incidently, is that a typo for "object array"; the string's built
> by "C string" "concatenation").
Yes, I think so. Hmm, it looks like you have object arrays floating
around which seems strange.
But, as I thought more about multiple inheritance I realized that there
really is a case for a container class like UserArray that you can
inherit from that only "wraps" the ndarray and does not try to inherit
from it.
The analogy I see with C-code is that a container class has a pointer to
an array object structure, while a sub-class has the arrayobject
structure itself as part of the new subclass.
So, I added back the UserArray to numpy. Now, you can inherit from
numpy.lib.UserArray.UserArray just like before.
> Ideas?
>
> The C type "actImage" looks like:
> typedef struct actImage {
> int nrow; // number of rows
> int ncol; // number of columns
> void *base; // allocated memory, if owned by this
> object
> int baseRefCount; // reference counter for base
> double **rows; // Fluxes for pixels
> PyArrayObject *_array; // pointer to Numeric array; used
> by actNumPy
> } actImage;
It looks like you have a "container" class by default here. You could,
if you wanted make this a subclass by definining actImage as
typedef struct actImage {
PyArrayObject _array;
int nrow; // redundant
int ncol; // redundant
void * base; // also seems redundant
int baseRefCount; // perhaps not necessary either
double **rows; // truly new information
} actImage;
Now, a pointer to actImage could be cast to a (PyArrayObject *) and used
wherever arrayobjects are expected and work just fine.
I'm not sure why you have a different pointer for allocated memory which
could
It seems to me that you should create a sub-type in C of the ndarray
rather than a container class. But, a container class would also
continue to work. With the re-addition of UserArray it would work in
much the same way as well.
> The _array is set in the C actImage constructor with:
> im->_array = (PyArrayObject *)PyArray_FromDimsAndData(2, dims,
> PyArray_DOUBLE, (void *)im->base);
>
For the subclass you would need to do a little more work in the
constructor because PyArray_FromDims returns only a filled-in
PyArrayObject structure. You could copy all the elements of this array
over (this wouldn't copy data just pointers), and then delete the
PyArrayObject structure (don't use DECREF, just tp_free). Then you
could fill in the rest of the actImage structure.
> and getArray is a wrapper around:
>
> PyObject *actImageGetNumPy(const actImage *im)
> {
> Py_XINCREF(im->_array);
> return PyArray_Return(im->_array);
> }
>
You could use the new tp_members structure here which allows you to get
access to parts of your C-structure very easily.
The easiest transition path is to just use the re-added UserArray as
before. If you want to learn to sub-class, that could be done as
well. But, there are no sub-classes in C that I know of yet, so
although it is possible, there may be some subtle issues uncovered in
the process.
-Travis
More information about the Numpy-discussion
mailing list