July 2002
Intermediate to advanced
608 pages
15h 46m
English
Credit: Luther Blissett
You have an existing C function that takes as an argument a C array of C-level values (e.g., doubles), and want to wrap it into a Python callable C extension that takes as an argument a Python sequence (or iterator).
The easiest way to accept an arbitrary Python sequence in the Python
C API is with the PySequence_Fast function, which
builds and returns a tuple when needed, but returns only its argument
(with the reference count incremented) if the argument is already a
list:
#include <Python.h>
/* a preexisting C-level function you want to expose -- e.g: */
static double total(double* data, int len)
{
double total = 0.0;
int i;
for(i=0; i<len; ++i)
total += data[i];
return total;
}
/* here is how you expose it to Python code: */
static PyObject *totalDoubles(PyObject *self, PyObject *args)
{
PyObject* seq;
double *dbar;
double result;
int seqlen;
int i;
/* get one argument as a sequence */
if(!PyArg_ParseTuple(args, "O", &seq))
return 0;
seq = PySequence_Fast(seq, "argument must be iterable"); if(!seq) return 0; /* prepare data as an array of doubles */ seqlen = PySequence_Fast_GET_SIZE(seq); dbar = malloc(seqlen*sizeof(double)); if(!dbar) { Py_DECREF(seq); return PyErr_NoMemory( ); } for(i=0; i < seqlen; i++) { PyObject *fitem; PyObject *item = PySequence_Fast_GET_ITEM(seq, i); if(!item) { Py_DECREF(seq); free(dbar); return 0; } fitem = PyNumber_Float(item); if(!fitem) ...