[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!