Reputation: 48725
I am creating a python wrapper for a scientific C library that I have written. The library contains a constant array of doubles that are defined globally at compile-time, i.e
const double arr[NARR] = { 200.0, 201.0, ... 899.0, 900.0 };
I want to use SWIG make this a module-level numpy array in my python module, i.e.
>>> import foo
>>> foo.arr
array([200.0, 201.0, ..., 889.9, 900.0])
I can't seem to find anything in the docs to do this with a constant array. Everything seems to deal with returning numpy arrays from functions, or defining non-array constants.
I know how to do this by wrapping the array manually:
npy_intp dim[1] = { NARR };
PyObject *a = PyArray_SimpleNewFromData(1, dim, NPY_DOUBLE, arr);
PyObject_SetAttrString(module, "arr", a);
I just can't get it to work with SWIG. When I try to put the above code in the init block of my foo.i file, the "arr" variable does not show up in the foo module.
Can anybody tell me how to get this to work properly?
EDIT
Changed code example for wrapping the array manually based on the suggestion from seberg.
Upvotes: 1
Views: 331
Reputation: 48725
I have found a solution to this issue, but it is pretty hackish.
I have included two code extensions in my foo.i
file, one in C and the other in python. The C extension creates a function that returns the C array, along with a statement that tells SWIG to create a wrapper that returns this C array as a numpy array:
/* Tell SWIG I want the function to output a numpy array */
%apply double ARGOUT_ARRAY1[ANY] { double a[NARR] };
/* Create a function that returns a copy of the array */
%inline %{
void _get_arr(double a[NARR]) {
for (int i = 0; i < NARR; i++)
a[i] = arr[i];
}
%}
The python extension calls this function and places it into the module-level numpy array variable arr
(and I make it read-only for good measure):
%pythoncode %{
# Make the arr array a read-only module-level numpy array
arr = _get_arr()
arr.flags.writeable = False
%}
Because I am going to distribute this as a package, I can control the functions that are imported in the __init__.py
file and therefore _get_arr
will not be imported with foo
.
I now get the desired results:
>>> import foo
>>> foo.arr
array([200.0, 201.0, ..., 889.9, 900.0])
>>> foo.arr[0] = 10
RuntimeError: array is not writeable
>>> foo._get_arr()
AttributeError: 'module' object has no attribute '_get_arr'
Upvotes: 1