UserPreferences

ExtendingPython


1. Extending Python

There are two main methods of extending Python: the first is to take existing code (say C or C++) and create wrappers around it using SWIG. The second is to write code (C or C++) that take existing Python objects and manipulate them. We'll explore the second method here.

1.1. Manipulation of Python Objects in C

Imagine that you have some computation that you would rather do in C than in Python. Let's say we want to multiply two numbers together. Here's how we want it to work in Python:

>>> import somelib
>>> somelib.processIt("test string", 23, 56)
The string is 'test string'
1288

Let's make our somelib be "_cconx" (the initial underscore is a hint that this module is coming from a foreign language).

First, we create the C file that contains the special Python-C function API for creating, parsing, and manipulating Python objects in C:

#include <Python.h>

static PyObject *processIt(PyObject *self, PyObject *args){

  int width, height, size;
  char *name;

  PyObject *buffer, *tuple;

  if(!PyArg_ParseTuple(args, "sii", &name, &width, &height)){
    PyErr_SetString(PyExc_TypeError, "Invalid arguments to processIt");
    return NULL;
  }

  printf("The name is '%s'\n", name);
  size = width * height;

  return Py_BuildValue("i", size);
}

static PyMethodDef cconxMethods[] = {
  {"processIt", processIt, METH_VARARGS, "Given a str, i, i return i * i"},
  {NULL, NULL, 0, NULL}
};

void init_cconx(void){
  (void) Py_InitModule("_cconx", cconxMethods);
}

We then compile it using a Makefile:

% make

where the Makefile has:

PYTHON_INCLUDE=-I/usr/include/python2.2/

SO = .so # on windows it might be .dll

_cconx$(SO): cconx.o
        $(LD)  -shared cconx.o -o _cconx$(SO)

cconx.o: cconx.c
        $(CC) $(PYTHON_INCLUDE) $(CCSHARED) $(CFLAGS) -c cconx.c

clean:
        $(RM) *.o *.so

You'll need to find your version of Python.h (try locate Python.h).

That's it. You just need to import it:

>>> import _cconx
>>> _cconx.processIt("test string", 23, 56)
The string is 'test string'
1288

processIt can be used like any other Python function.