[Numpy-discussion] Troubles with arrays, proposal for Solution

Phil Austin phil at geog.ubc.ca
Mon Jul 30 18:29:20 EDT 2001


Vanroose Wim writes:
 > Dear Numerical Python Users,
 > 
 >        It is now clear to me, after the comments of Travis Oliphant, 
 > Paul Dubois and Phil Austin,  that in EVERY C-file that uses NumPy 
 > extensions, the  "import_array" statement must be present.

Actually, what I was trying to say (in a message that didn't
make it to the list) is the opposite -- import_array must be
present in only one file.

So below I would do something like: (my additions marked by PA>)

 > 
 > /////////////////////////
 > //file: arraytest.h
 > //////////////////////
 > 
 > #include "Python.h"
PA> #define PY_ARRAY_UNIQUE_SYMBOL paArray
 > #include "arrayobject.h"
 > 
 > double *myTest(void);
 > 
 > //////////////////////
 > // file: arraytest.c
 > ////////////////////
 > 
PA> #define NO_IMPORT_ARRAY
 > #include "arraytest.h"
 > 
 > double * myTest(void ){
 >   double *result;
 >   ...
 >   
 >   return result; 
 > }
 > 
 > ////////////////////
 > //file: test.c   
 > ////////////////
 > #include "arraytest.h"
 > 
 > static PyObject *function(PyObject *self, PyObject *args){
 >   
 >   ...
 >   int dimensions[2];  
 >   
 >   dimensions[0] = N;
 >   dimensions[1] = N;
 > 
 >   PyArrayObject *result ;
 >   result = (PyArrayObject *)PyArray_FromDims(2,dimensions,PyArray_DOUBLE);
 > 
 >   double *data;
 >   data = myTest();
 >   memcpy(result->data,data,N*N*sizeof(double));
 >   return PyArray_Return(result);  
 > }
 > 
 > static PyMethodDef testMethods[] = {
 >   {"test",function,1},
 >   {NULL,NULL}
 > };
 > 
 > extern "C" {
 > void  inittest(){
 >   PyObject *m,*d;
 >   m = Py_InitModule("test", testMethods);
 >   import_array();
 >   d = PyModule_GetDict(m);
 > }
 > 


You should see the following when you run /lib/cpp -E on these
files:

in arraytest.c

 #define NO_IMPORT_ARRAY
 #include "arraytest.h"

will produce a line like:

extern void **paArray;


but in  test.c

#include "arraytest.h"

will produce:

void **paArray;

and 

import_array();

will expand to


    { PyObject *numpy = PyImport_ImportModule("_numpy"); if (numpy !=
    0) { PyObject *module_dict = PyModule_GetDict(numpy); PyObject
    *c_api_object = PyDict_GetItemString(module_dict, "_ARRAY_API");
    if (((c_api_object)->ob_type == &PyCObject_Type)) { paArray =
    (void **)PyCObject_AsVoidPtr(c_api_object); } } };


The result is that there is a single global function pointer
array called paArray that has its space reserved in test.c, and
is referenced externally in arraytest.c.  This allows you to use
any numeric api call in either file.

If you compile the module to, say, test.so on unix you should see something
like this when you do a nm -D:

~phil% nm -D test.so | grep paArray
000a3d00 B paArray

i.e. one instance of paArray in the data segment of the so file.

Scanning the output of /lib/cpp -E output is a good way
to get a feel for this (on unix anyway).

Regards, Phil







More information about the NumPy-Discussion mailing list