[Numpy-discussion] NumPtr vs NumPy.i to access C

Dag Sverre Seljebotn dagss@student.matnat.uio...
Sat May 17 18:42:57 CDT 2008

Jose Martin wrote:
> Hi, I'd like to access a C function from python, and the function takes
> input/output arrays. I'd probably use SWIG to do the interface to the C
> code. I found 2 options:
> -NumPtr module, to access Numeric arrays as pointers
> http://www.penzilla.net/tutorials/python/numptr/
> - numpy.i, a SWIG interface file for NumPy that defines typemaps
> http://projects.scipy.org/scipy/numpy/browser/trunk/numpy/doc/swig/doc/numpy_swig.html
> I'm not sure if there is significant differences between the 2 options
> (besides using either NumPy or Numeric). Does numpy.i interface file use
> pointers to access NumPy arrays? or does it make a copy of the array to
> pass it to/from the C function?

I'll use the opportunity to recommend Cython, http://cython.org.
(Disclaimer: I am not objective as I am very involved with Cython
development, in particular I'll spend this summer improving NumPy support
in it. You should listen to others on SWIG.)

Cython is a different approach from SWIG (see
http://wiki.cython.org/WrappingCorCpp; in particular SWIG uses more layers
of indirection).

To wrap a function, say, dealing with a 2-D float64 NumPy array, you'd
write the following Cython code (Cython is a seperate language, sort of a
mix of Python and C):

import numpy
cimport numpy


cdef extern from "your_c_header.h":
    int your_func(numpy.float64* buf, unsigned int width, unsigned int

def call_your_func(numpy.ndarray arr):
    if arr.ndim != 2: raise ValueError("Need 2D array")
    # ... and so on. Better make sure array is C-contiguous too!
    # (or convert it)

    return your_func(<numpy.float64*>arr.data, arr.shape[0], arr.shape[1])

After Cython compilation you get a C file, and after compiling the C file
you can import it into Python like a normal module and call
"call_your_func" directly.

That's an overview. Basically, "arr" behaves exactly like a Python object,
except for when accessing the fields in which case values from the
underlying C implementation will be returned instead. More info can be
found on cython.org etc. (or ask!).

Dag Sverre

PS. You'll need an "numpy.pxd" (put it in the same directory, the
"cimport" pulls it in). Here's mine:

cdef extern from "Python.h":
    ctypedef int Py_intptr_t

cdef extern from "numpy/arrayobject.h":
    ctypedef class numpy.ndarray [object PyArrayObject]:
        cdef char *data
        cdef int ndim "nd"
        cdef Py_intptr_t *shape "dimensions"
        cdef Py_intptr_t *strides

    cdef void import_array()

    ctypedef float npy_float64
    ctypedef float npy_float80
    ctypedef int npy_int8
    ctypedef int npy_uint8
    ctypedef int npy_int32
    ctypedef int npy_uint32
    ctypedef int npy_int64
    ctypedef int npy_uint64

More information about the Numpy-discussion mailing list