In [1]:
from IPython.display import display, Markdown;

In [2]:
def print_code(path, lang=""):
    with open(path) as f:
        return Markdown("```%s\n%s```" % (lang,f.read()));

Notes: Interfacing with C

Python-C-API

The Python-C-API is the backbone of the standard Python interpreter. Using this module it is possible to write Python extension modules in C and C++. Using this module often requires significant boilerplate code to convert between datatypes.

Using the Python-C-API is not recommended in practice, but it is useful to understand because other methods rely on the concepts in this section.

Advantages

  • Requires no additional libraries
  • Lots of low-level control
  • Entirely usable from C++

Disadvantages

  • May require a substantial amount of effort
  • Significant overhead
  • Must be compiled
  • High maintenance cost
  • No forward compatibility across Python versions as C-API changes
  • Reference count bugs are easy to create and hard to find

C-extension module

We will create an extension module based on the following C code, which simply wraps the cos method from math.h.


In [3]:
print_code("python-c-api/cos_module.c", "c")


Out[3]:
/*  Example of wrapping cos function from math.h with the Python-C-API. */

#include <Python.h>
#include <math.h>

/*  wrapped cosine function */
static PyObject* cos_func(PyObject* self, PyObject* args) {
    double value;
    double answer;

    /*  parse the input, from python float to c double */
    if (!PyArg_ParseTuple(args, "d", &value))
        return NULL;
    /* if the above function returns -1, an appropriate Python exception will
     * have been set, and the function simply returns NULL
     */

    /* call cos from libm */
    answer = cos(value);

    /*  construct the output from cos, from c double to python float */
    return Py_BuildValue("f", answer);
}

/*  define functions in module */
static PyMethodDef CosMethods[] = {
     {"cos_func", cos_func, METH_VARARGS, "evaluate the cosine"},
     {NULL, NULL, 0, NULL}
};

/* module initialization */
PyMODINIT_FUNC initcos_module(void) {
     (void) Py_InitModule("cos_module", CosMethods);
}

Compiling the Extension

The following setup.py file uses distutils to compile the C extension.


In [4]:
print_code("python-c-api/setup.py", "python")


Out[4]:
from distutils.core import setup, Extension;

# define the extension module
cos_module = Extension('cos_module', sources=['cos_module.c']);
# run setup
setup(ext_modules=[cos_module]);

We now call setup.py with the following options:

  • build_ext builds extension modules
  • --inplace will output the compiled extension module into the current directory

In [12]:
%%bash
cd python-c-api
python setup.py build_ext --inplace


running build_ext

Now we see that a new .so file has been created:


In [15]:
%%bash
ls


build
python-c-api
Scipy - Interfacing Python with C.ipynb

Importing the Extension


In [17]:
import cos_module.cpython-35m-x86_64-linux-gnu as cos_module


  File "<ipython-input-17-1f8a4809caec>", line 1
    import cos_module.cpython-35m-x86_64-linux-gnu as cos_module
                             ^
SyntaxError: invalid syntax

In [ ]:


In [ ]: