[Tutor] Calling C from Python [C wrapper writing]
Daniel Yoo
dyoo@CSUA.Berkeley.EDU
Fri, 20 Sep 2002 15:05:54 -0700 (PDT)
On Fri, 20 Sep 2002, Danny Yoo wrote:
>
>
> On Fri, 20 Sep 2002, Carlos Bergelin wrote:
>
> > Hi everybody!
> > I just want to know how can I do to call a C function from python?
>
> Hi Carlos,
>
> You can write a "wrapper" to make C functions look like Python
> functions. There' s a good utility called SWIG that makes wrapper
> writing fairly easy:
>
> http://www.swig.org/
>
> It usually involves telling SWIG what the function interface looks like.
> >From there, SWIG will generate the necessary code in C to make it
> accessible to Python.
>
> If you're curious about how all this actually works, you can take a look
> at the Extending and Embedding Document:
>
> http://python.org/doc/current/ext/ext.html
The key part in writing a wrapper is translating things from C values to
Python values. If you want to see what a wrapper might look like if we
don't use SWIG, you can take a good below:
I'm starting to polish up my wrapper on a "Lovin-style" string stemmer:
http://hkn.eecs.berkeley.edu/~dyoo/python/lovin_stemmer/
The original source code I took provides a 'stem()' function that reads in
a char* and does an in-place modification of the string. Python strings,
however, are immutable --- they're not supposed to be modified in place!
The wrapper tries to reconcile these two views of strings by using a
temporary holding variable.
/******/
static PyObject* LovinStemmer_stem(PyObject *module, PyObject *args) {
char *word;
PyObject *stemmed_word;
unsigned char *temp_str;
if (! PyArg_ParseTuple(args, "s", &word)) {
return NULL;
}
temp_str = malloc(sizeof(char) * (strlen(word) + 1 + 1));
/* Explanation for the "+ 1 + 1" part of the malloc: +1 for the
first character, which actually stores the string length, and +1
for NULL termination. */
strncpy(temp_str+1, word, strlen(word));
temp_str[0] = strlen(word);
_stem(temp_str);
stemmed_word = PyString_FromStringAndSize(temp_str+1, temp_str[0]);
free(temp_str);
return stemmed_word;
}
/******/
Here, my wrapper does a string copy before calling the real stem()
function. Once the original C function is done, I go back and then create
a new Python string. So my rough wrapper for the C stem() function is
simple, but a little tedious. And that's where SWIG comes in: it does
most of the tedium for us.
Anyway, hope this helps!