C Extension Module using Python
Last Updated :
27 Mar, 2019
Writing a simple C extension module directly using Python’s extension API and no other tools. It is straightforward to make a handcrafted extension module for a simple C code. But first, we have to make sure that the C code has a proper header file.
Code #1 :
#include <math.h>
extern int gcd( int , int );
extern int in_mandel( double x0, double y0, int n);
extern int divide( int a, int b, int *remainder);
extern double avg( double *a, int n);
typedef struct Point
{
double x, y;
} Point;
extern double distance(Point *p1, Point *p2);
|
The header would correspond to a library that has been separately compiled. The code below illustrates the basics of writing extension functions, following this assumption.
Code #2:
# include "Python.h"
# include "sample.h"
static PyObject * py_gcd(PyObject * self, PyObject * args)
{
int x, y, result;
if (! PyArg_ParseTuple(args, "ii" , &x, &y))
{
return NULL;
}
result = gcd(x, y);
return Py_BuildValue( "i" , result);
}
static PyObject * py_divide(PyObject * self, PyObject * args)
{
int a, b, quotient, remainder;
if (! PyArg_ParseTuple(args, "ii" , &a, &b))
{
return NULL;
}
quotient = divide(a, b, &remainder);
return Py_BuildValue( "(ii)" , quotient, remainder);
}
|
Code #3 : Module method table and structure
static PyMethodDef SampleMethods[] =
{
{ "gcd" , py_gcd, METH_VARARGS, "Greatest common divisor" },
{ "divide" , py_divide, METH_VARARGS, "Integer division" },
{ NULL, NULL, 0, NULL}
};
static struct PyModuleDef samplemodule =
{
PyModuleDef_HEAD_INIT,
"sample" ,
"A sample module" ,
-1,
SampleMethods
};
PyMODINIT_FUNC
PyInit_sample( void )
{
return PyModule_Create(&samplemodule);
}
|
Code #4: Creating a setup.py
python file for building the extension module.
from distutils.core import setup, Extension
setup(name = 'sample' ,
ext_modules = [
Extension( 'sample' ,
[ 'pysample.c' ],
include_dirs = [ '/some/dir' ],
define_macros = [( 'FOO' , '1' )],
undef_macros = [ 'BAR' ],
library_dirs = [ '/usr/local/lib' ],
libraries = [ 'sample' ]
)
]
)
|
Code #5: Now simply use python3 buildlib.py build_ext --inplace
, to build the resulting library.
bash% python3 setup.py build_ext --inplace
running build_ext
building 'sample' extension
gcc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
-I/usr/local/include/python3.3m -c pysample.c
-o build/temp.macosx-10.6-x86_64-3.3/pysample.o
gcc -bundle -undefined dynamic_lookup
build/temp.macosx-10.6-x86_64-3.3/pysample.o \
-L/usr/local/lib -lsample -o sample.so
bash %
The above code will create a shared library called sample.so.
Code #6 :
import sample
print ( "gcd = " , sample.gcd( 35 , 42 ))
print ( "\ndistance : " , sample.divide( 42 , 8 ))
|
Output :
gcd = 7
distance = (5, 2)
“Extending and Embedding the Python Interpreter” is a Python’s documentation that can be consulted before attempting any kind of handwritten extension.
In extension modules, functions can be written as shown in code snippet below.
Code #4 :
static PyObject * py_func(PyObject * self , PyObject * args)
{
...
}
|
- PyObject – C data type that represents any Python object. At a very high level, an extension function is a C function that receives a tuple of Python objects (in
PyObject *args
) and returns a new Python object as a result. The self argument to the function is unused for simple extension functions, but comes into play should you want to define new classes or object types in C.
- The
PyArg_ParseTuple()
function is used to convert values from Python to a C representation. As input, it takes a format string that indicates the required values, such as “i” for integer and “d” for double, as well as the addresses of C variables in which to place the converted results.
Py_BuildValue()
function is used to create Python objects from C data types. It also accepts a format code to indicate the desired type. In the extension functions, it is used to return results back to Python. One feature of Py_BuildValue()
is that it can build more complicated kinds of objects, such as tuples and dictionaries.
Share your thoughts in the comments
Please Login to comment...