Department of Engineering

IT Services

Python and C/C++

This page shows how to write C and C++ programs that can be called from python. Extending and Embedding the Python Interpreter has more information.

C

This uses an example from Extending Python with C or C++, providing more information on how to make it work on Linux but less information on why it works

  • This example is going to call the system function. It's going to make this callable via a system call in a package called spam. Create a file called spammodule.c containing this
    #include <Python.h>
    
    static PyObject *
    spam_system(PyObject *self, PyObject *args);
    
    static PyMethodDef SpamMethods[] = {
        {"system",  spam_system, METH_VARARGS,
         "Execute a shell command."},
        {NULL, NULL, 0, NULL}        /* Sentinel */
    };
    
    PyMODINIT_FUNC
    initspam(void)
    {
        (void) Py_InitModule("spam", SpamMethods);
    }
    
    static PyObject *
    spam_system(PyObject *self, PyObject *args)
    {
        const char *command;
        int sts;
    
        if (!PyArg_ParseTuple(args, "s", &command)) /* provide a char[] */
            return NULL;
        sts = system(command);
        return Py_BuildValue("i", sts); /* return int */
    }
    
    
    int
    main(int argc, char *argv[])
    {
        /* Pass argv[0] to the Python interpreter */
        Py_SetProgramName(argv[0]);
    
        /* Initialize the Python interpreter.  Required. */
        Py_Initialize();
    
        /* Add a static module */
        initspam();
    }
    
  • Create a file called setup.py containing this
    from distutils.core import setup, Extension
    
    module1 = Extension('spam',
                        sources = ['spammodule.c'])
    
    setup (name = 'PackageName',
           version = '1.0',
           description = 'This is a demo package',
           ext_modules = [module1])
    
  • Run
       python setup.py build
    
    This should create a folder called build. Inside that folder there should be some sub-folders, one of which should contain a file called spam.so. It's that sub-folder which you need to mention in the next stage. On my machine the sub-folder's called lib.linux-x86_64-2.6
  • Type
        export PYTHONPATH=build/lib.linux-x86_64-2.6
    
  • From python, run
    import spam
    status = spam.system("ls -l")
    

You should see a list of files that are in the current folder.

C++

This example shows how to interface with some user-written C++ code. It doesn't try to emulate full C++ functionality from python.

  • Create a file with your code in it. Here I'll call it class.cc because it uses classes.
    #include <iostream>
    #include <string>
    using namespace std;
    
    class testing {
    public:
      int a;
      string b;
      int doubling(int);
    };
    
    int testing::doubling(int i) {
      return i*2;
    }
    
    int blah(int num) {
      testing t;
      t.a=999;
      t.b="string";
      int c=t.doubling(num);
      cout << "c=" << c << endl;
      return c;
    }
    
    
  • Create a file to set up the interfacing. I've call it classymodule.cc. It needs to contain the name of the module (in this case classy) and the routines (in this case blah) provided by the module. The "i" in the PyArg_ParseTuple and Py_BuildValue calls means that an integer values is used. An alternative is "s".
    #include <Python.h>
    int blah(int num);
    
    static PyObject *
    classy_blah(PyObject *self, PyObject *args);
    
    static PyMethodDef ClassyMethods[] = {
        {"blah",  classy_blah, METH_VARARGS,
         "Execute a command."},
        {NULL, NULL, 0, NULL}        /* Sentinel */
    };
    
    PyMODINIT_FUNC
    initclassy(void)
    {
        (void) Py_InitModule("classy", ClassyMethods);
    }
    
    static PyObject *
    classy_blah(PyObject *self, PyObject *args)
    {
        int command;
        int sts;
    
        if (!PyArg_ParseTuple(args, "i", &command))
            return NULL;
        sts = blah(command);
        return Py_BuildValue("i", sts);
    }
    
    int
    main(int argc, char *argv[])
    {
        /* Pass argv[0] to the Python interpreter */
        Py_SetProgramName(argv[0]);
    
        /* Initialize the Python interpreter.  Required. */
        Py_Initialize();
    
        /* Add a static module */
        initclassy();
    }
    
  • Create a file called tryclassy.py containing this
    from distutils.core import setup, Extension
    
    module1 = Extension('classy',
                        sources = ['classymodule.cc','class.cc'])
    
    setup (name = 'PackageName',
           version = '1.0',
           description = 'This is a demo package',
           ext_modules = [module1])
    
  • Run
       python setup.py build
    
    This should create a folder called build. Inside that folder there should be some sub-folders, one of which should contain a file called classy.so. It's that sub-folder which you need to mention in the next stage. On my machine the sub-folder's called lib.linux-x86_64-2.6
  • Type
        export PYTHONPATH=build/lib.linux-x86_64-2.6
    
  • From python, run
    import classy
    
    status = classy.blah(3)
    
    class Pythesting:
        """A simple example class"""
        a=1
        b="hello"
        def doubling(self,i):
            classy.blah(i)
    
    x = Pythesting()
    x.doubling(6)
    

C++ using SWIG

You may need to make available from Python more of the class-related behaviour of the C++ code than the previous example provided. swig can automatically generate the interface code. See Extending Python with C++ for details. Here a short example will be provided.

This C++ code

#include <iostream>
using namespace std;

class Storage {
public:
  Storage() { value=999; }
  Storage(int v) { value=v; }
  int value;
  int doublevalue() { return value*2; }
};

int main()
{
  Storage s1, s2(7);
  cout << "s1.value=" <<s1.value 
       <<" s2.value=" <<s2.value 
       <<" s2.doublevalue()=" << s2.doublevalue() << endl;
}

can be translated into python as

class Storage:
   def __init__(self,v = 999):
       self.value = v
   def doublevalue(self):
       return self.value*2

s1=Storage()
s2=Storage(7)

print  "s1.value=", s1.value, " s2.value=", s2.value, " s2.doublevalue()=", s2.doublevalue() 

but let's suppose that doublevalue is a complicated C++ function that we don't want to convert into Python. How can we interface the Python and C++ code? First create these 3 files

storing.h
// storing.h
class Storage {
public:
  Storage();
  Storage(int v);
  int value;
  int doublevalue();
};
storing.cc
// storing.cc
#include "storing.h"

Storage::Storage() { value=999; }
Storage::Storage(int v) { value=v; }
int Storage:: doublevalue() { return value*2; }
storing.i
%module storing

%{
#include "storing.h"
%}

%include "storing.h"

Then run

   swig -c++ -python storing.i

If this succeeds it will silently create storing_wrap.cxx (which is likely to be rather large). Then create this file

setup.py
from distutils.core import setup, Extension

storing_module = Extension('_storing', sources=['storing_wrap.cxx', 'storing.cc'])

setup(name='storing', version='0.1', 
      author='My Name', 
      description="""Storing SWIG Module.""", 
      ext_modules=[storing_module], py_modules=['storing'])

and run

     python setup.py build_ext --inplace

This will display some compile lines and may produce a warning message

storing_wrap.cxx:2796: warning: 'argv[0]' may be used uninitialized in this function

Don't worry. You should now be able to run this in python

from storing import *

s1=Storage()
s2=Storage(7)

print  "s1.value=", s1.value, " s2.value=", s2.value, " s2.doublevalue()=", s2.doublevalue() 

and get the output

      s1.value= 999  s2.value= 7  s2.doublevalue()= 14