|
|
|||
![]() |
Department of Engineering |
| University of Cambridge > Engineering Department > computing help > Languages |
Contents 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.
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
#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();
}
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])
python setup.py buildThis 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
export PYTHONPATH=build/lib.linux-x86_64-2.6
import spam
status = spam.system("ls -l")
You should see a list of files that are in the current folder.
This example shows how to interface with some user-written C++ code. It doesn't try to emulate full C++ functionality from python.
#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;
}
#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();
}
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])
python setup.py buildThis 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
export PYTHONPATH=build/lib.linux-x86_64-2.6
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)
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
| | Languages | computing help | |