UserPreferences

PythonAndC


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

Modules

  1. PyroModuleIntroduction

  2. PyroModuleObjectOverview

  3. PyroModulePythonIntro

  4. PyroModuleDirectControl

  5. PyroModuleSequencingControl

  6. PyroModuleBehaviorBasedControl

  7. PyroModuleReinforcementLearning

  8. PyroModuleNeuralNetworks

  9. PyroModuleEvolutionaryAlgorithms

  10. PyroModuleComputerVision

  11. PyroModuleMapping

  12. PyroModuleMultirobot

  13. FurtherReading

Additional Resources

  1. PyroIndex

  2. PyroAdvancedTopics

  3. PyroUserManual

  4. [WWW]Pyro Tutorial Movies

Reference: PyroSiteNotes