Python and C via SWIG
This module will give you some hints about writing code in C or C++, and calling from it from Python. This is just a glimpse of what is possible. For a complete reference, see the documentation available at http://www.swig.org/.
A simple example can also be found at ExtendingPython.
In the following, all of the lowercase filenames are created by you, and all of the Uppercase filenames are created by the system.
First, let's consider a simple C example:
/* file: code.c */
#include <stdio.h>
#include "code.h"
int process(double d) {
int retval = 0;
printf("You passed in a %f!\n", d);
retval = (int) (d * 2);
return retval;
}
and its associated header file:
/* code.h */ #ifndef __CODE_H__ #define __CODE_H__ int process(double d); #endif
To wrap this code using SWIG, you need a .i file. Here is code.i:
%module code
%{
#include "code.h"
%}
%include code.h
That's it for code. Now, the most confusing part, the Makefile:
CC = g++
PYTHON_INCLUDE = -I /usr/include/python2.2/
LIBS= -lstdc++ -ldl -lpthread -lswigpy
CPPFLAGS = -Wall -Wno-unused -D_POSIX_THREADS \
-D_POSIX_THREAD_SAFE_FUNCTIONS \
-D_REENTRANT -DPOSIX \
-D__x86__ -D__linux__ \
-D__OSVERSION__=2 -frepo -DUSINGTHREADS -DLINUX -D_GNU_SOURCE \
-L /usr/X11R6/lib -L /usr/local/lib/
_code.so: code.o Code.o
$(CC) $(CPPFLAGS) $(PYTHON_INCLUDE) -shared code.o Code.o -o $@ $(LIBS)
Code.o: Code.cc
$(CC) -c $(PYTHON_INCLUDE) Code.cc -o $@
Code.cc: code.i code.h
swig -python -c -o Code.cc code.i
code.o: code.h code.c
$(CC) $(CPPFLAGS) -c code.c -o code.o
clean:
$(RM) -f *.o *~ *.so *.cc *.pyc code.py
Running make will produce _code.so and code.py. To use:
% python >>> import code >>> code.process(45) You passed in a 45.000000! 90 >>>
C++ is very similar: you don't need the -lswigpy, and change the -c flag to swig to -c++.
Dealing with Python types in C
Next, we explore using (receiving and returning) Python data structures in C.
First, you will need to include the path to Python.h when you compile. In the above Makefile, you would just add $(PYTHON_PATH) to the compile line of code.c. Also, add #include <Python.h> to your c code.
Raising Exceptions
If in your c code you want to raise an exception (ie, something goes wrong, or is not what you expected), call the PyErr_SetString() function, and return NULL.
If you encounter an error when you are in a C++ constructor, don't return NULL though.
if (something_bad) {
PyErr_SetString(PyExc_IOError, "Filename: some useful IO error message");
// put clean up code in here
return NULL;
}
You can use any of the PyExc errors: PyExc_IOError, PyExc_TypeError, etc.
Receiving a Python Object
Strings (char arrays), integers, floats, and doubles are automatcally handled for you by SWIG, so you don't need to do anything special.
If you want to take a more complex Python object (a list for example), you will need to handle that yourself.
Here is an example that takes 5 arguments. You could have done this without calling PyArgParseTuple and just put the 5 args in the function call.
static PyObject *function(PyObject *self, PyObject *args){
char *device;
int width, height, color, channel;
PyObject *buffer, *tuple;
//call with: function(device_name, width, height, color, channel)
if(!PyArg_ParseTuple(args, "siiii", &device, &width, &height, &color, &channel)){
PyErr_SetString(PyExc_TypeError, "Invalid arguments to function");
return NULL;
}
... // do stuff with the args
}
Here is another function that takes a tuple of tuples:
PyObject *function(PyObject *tuple) {
if (!PyTuple_Check(tuple)) {
PyErr_SetString(PyExc_TypeError, "Invalid tuple to function()");
return NULL;
}
for (int i = 0; i < PyTuple_Size(tuple); i++) {
PyObject *someTuple = PyTuple_GetItem(tuple, i);
// for each someTuple:
for (int count = 0; count < PyTuple_Size(someTuple); count++) {
thing = PyTuple_GetItem(someTuple, count);
... // do something with thing
}
}
}
Returning a Python Object
PyObject *makeList(int x) {
PyObject *myList = PyList_New(0);
for (int i = 0; i < x; i++) {
PyList_Append(myList, Py_BuildValue("i", i));
}
return myList;
}
Pyro Modules Table of Contents
-
Pyro - Back to Pyro main page
-
Beyond Legos - NSF grant that pays for Pyro
Modules
Additional Resources
Reference: PyroSiteNotes
