This part is used for those who want to build faster functions in c/c++
, and import the xxx.so
or xxx.dll
in python, so that the overall codes can run faster with the embedded c/c++
languages supports.
1. C Foreign Function Interface (CFFI)
CFFI <https://cffi.readthedocs.io/en/latest/>
provide a simple to use mechanism for interfacing with C from CPython and PyPy. It supports two model:
- a inline ABI compatibility model, you can dynamically load and run functions from executable modules
- an API model, can build C extension modules.
ABI Interaction
from cffi import FFI
ffi=FFI()
ffi.cdef("size_t strlen(const char*);")
clib=ffi.dlopen(None)
length=clib.strlne(String to be evaluated.)
#print:23
print("{}".format(length))
2. Ctypes
the ctypes modules provides C compatible data types and functions to load DLLs so that calls can be made to C shared libraries without having to modify them.
Simple C code to add two numbers, save it as add.c
// sample C file to add 2 numbers -int and floats
#include<stdio.h>
int add_int(int,int);
int add_float(float,float);
int add_int(int p,int q){ return p+q;}
float add_float(float p,float q){ return p+q;}
Next we compile the C file to a .so
file (or DLL
) :
gcc -shared -Wl,-soname,adder -o adder.so -fPIC add.c
Now in your python code:
from ctypes import *
# load the shared object file
adder=CDLL('./adder.so')
# Find sum of integers
res_int=adder.add_int(4,5)
print "Sum of 4 and 5 =" +str(res_int)
# >>> Sum of 4 and 5 = 9
# find sum of floats
a=c_float(5.5)
b=c_float(4.1)
add_float=adder.add_float
add_float.restype=c_float
print "Sum of 5.5 and 4.1 = ", str(add_float(1,b))
# >>> Sum of 5.5 and 4.1 = 9.60000038147
3. Simplified Wrapper and Interface Generator (SWIG)
In this method, the developer must develop an extra interface file which is an input to SWIG. This is a great method when you have a C/C++ code base, and you want to interface it to many different languages.
The C code example.c
that has avariety of functions and variables:
#include<time.h>
double my_variable=3.0;
int fact(int n){
if(n<1) return 1;
else return n*fact(n-1);
}
int my_mod(int x,int y){ return (x%y);}
char* get_time(){
time_t ltime;
time(<ime);
return ctime(<ime);
}
The interface file example.i
- this will remain the same irrespective of the language you want to port yout C code:
/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
%}
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
And compile it:
unix % swig -python example.i
unix % gcc -c example.c example_wrap.c \
-I/usr/local/include/python2.1
unix % ld -shared example.o example_wrap.o -o _example.so
Finally, the Python output:
>>> import example
>>> example.fact(5)
120
>>> example.my_mod(7,3)
1
>>> example.get_time()
'Sun Feb 11 23:01:07 1996'
It’s too complex.
4. C/Python API
Its the most widely used method - it’s simplicity and you can manipulate python objects in your C code.
All python object are represented as PyObject
struct which is defined in Python.h
header file. For example, if the PyObject
is also a PyListType
(basically a list), the we can use the PyList_Size()
for the length of the list ( equal to len(list)
). Most of the basic functions/operations are defined in Python.h
adder.c
:
// Python.h has all the required function definitions to manipulate the Python objects.
#include<Python.h>
// This is the function that is called from your python code
static PyObject* addList_add(PyObject* self,PyObject*args){
PyObject* ListObj;
//The input arguments come as a tuple, we parse the args to get the various variables
//In this case it's only one list variable, which will now be reference by ListObj
if(! PyArg_ParseTuple(atgs,"O",&ListObj)){
return NULL;
}
// length of the list
long length=PyList_Size(listObj);
//iterate over all the elements
int i,sum=0;
for(i=0;i<length;i++){
// get an element out of the list - the element is also a python objects
PyObject* temp=PyList_GetItem(listObj,i);
// we know that object reprsents an integer - so convert it into C long
long elem=PyInt_AsLong(temp);
sum+=elem;
}
// value returned back to python code - another python object
// build value here convers the C long a python integer
return Py_BuildValue("i",sum);
}
/* This table contains the relavent info mapping -
<function-name in python module>, <actual - function>,
<type-of-args the function expects>, <docstring associcated with the function>
*/
static PyMethodDef addList_funcs[]={
{"add",(PyCFunction)addList_add,METH_VARAGES,addList_docs},
{NULL,NULL,0,NULL}
};
/*
addList is the module name, add this is the initialization blockof the module.
<desired module name>,<the-info-table>,<module's-docstring>
*/
PyMODINIT_FUNC initaddList(void){
Py_InitModule3("addList", addList_funcs,
"Add all the lists");
}
- the
<Python.h>
file consists of all the required types (to represent Python Object types) and function definitions (to operate on the python objects). - Next we write the function which we plan to call from python. {module-name}_{function-name}, which in this case is
addList_add
. - Then fill in the information table - contains all the relevant information of the functions.
- the module initialization block which is of the signature
PyMODINIT_FUNC init{module-name}
Now we build the C module. Save the following code as setup.py
# build the modules
from distutils.core import setup, Extensions
setup(name="addList",version='1.0', ext_modules=[Extension('addList',['adder.c'])])
and run
python setup.py install
This should now build and install the C file into the python module we desire. After all this hard work, we’ll now test if the module works.
# module that talks to the C code
import addList
l=[1,2,3,4,5]
print "Sum of List - "+str(l)+" = " + str(addList.add(l))
Add here is the output
Sum of List - [1, 2, 3, 4, 5] = 15
So as you can see, we have developed our first successful C Python extension using the <Python.h>
API.