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.pyfrom 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