C Extension Module using Python

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 :

filter_none

edit
close

play_arrow

link
brightness_4
code

#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);

chevron_right


 
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:

filter_none

edit
close

play_arrow

link
brightness_4
code

# include "Python.h"
# include "sample.h"
  
/* int gcd(int, int) */
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);
}
  
/* int divide(int, int, int *) */
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);
}

chevron_right


 
Code #3 : Module method table and structure



filter_none

edit
close

play_arrow

link
brightness_4
code

/* Module method table */
static PyMethodDef SampleMethods[] =
{
    {"gcd", py_gcd, METH_VARARGS, "Greatest common divisor"},
    {"divide", py_divide, METH_VARARGS, "Integer division"},
    { NULL, NULL, 0, NULL}
};
  
/* Module structure */
static struct PyModuleDef samplemodule =
{
    PyModuleDef_HEAD_INIT,
    "sample", /* name of module */
    "A sample module", /* Doc string (may be NULL) */
    -1, /* Size of per-interpreter state or -1 */
    SampleMethods /* Method table */
};
  
/* Module initialization function */
PyMODINIT_FUNC
PyInit_sample(void)
{
    return PyModule_Create(&samplemodule);
}

chevron_right


 

Code #4: Creating a setup.py python file for building the extension module.

filter_none

edit
close

play_arrow

link
brightness_4
code

# setup.py
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']
                    )
            ]
)

chevron_right


 

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 :

filter_none

edit
close

play_arrow

link
brightness_4
code

import sample
  
print ("gcd = ", sample.gcd(35, 42))
  
print ("\ndistance : ", sample.divide(42, 8))

chevron_right


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 :

filter_none

edit
close

play_arrow

link
brightness_4
code

static PyObject *py_func(PyObject *self, PyObject *args)
{
    ...
}

chevron_right


 

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


My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.




Article Tags :

Be the First to upvote.


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.