Embedding & Extending Python

Python can be mixed with other languages (especially C) by:

Complete docs on python.org

Embedding Python

Programs can use libpython to run the Python interpreter

Trivial example (embed0.c):

#include <Python.h>

main(int argc,char **argv)
    PyRun_SimpleString("import time\n"
                       "print 'time =', time.time()\n");

Compile with the command:

cc -Xlinker -export-dynamic -I/usr/include/python embed0.c -o embed0 -L/usr/lib/python/config/ -lpython2.2 -ldl -lpthread -lutil -lm

The flags and libraries that a program needs to be linked with can be found using the script Linking.py

Embedding Python

One can also run the interpreter on files

Highlights of embed1.c:

    fp = fopen(filename, "r");
    PyRun_SimpleFile(fp, filename);


Embedding Python

Functions to use:

Call once, before any other Python functions
Call before exiting program

Executes Python code in a character string (char *)

PyRun_SimpleFile(filePointer, fileName)
Executes Python code in a file

Other functions exist for more advanced access to Python features (e.g. creating Python objects)

Embedding Python

pycave.c uses embedded Python to allow one to run a Python script in a CAVElib program

pycave calls 2 functions defined in the Python script:

Extending Python

C functions can be called from Python by extending Python

This involves defining a new module, that can be imported

The module has a table of function names and corresponding C functions to call for each

A function must parse Python objects that are the function arguments, and return a Python object

Extending Python

Example extension functions:

static PyObject* encrypt(PyObject *self, PyObject *args)
    char *string, *returnstring, *p;
    if (!PyArg_ParseTuple(args, "s", &string))
        return NULL;
    returnstring = strdup(string); 
    for (p=returnstring; *p; p++)
        *p = rot13(*p);
    return Py_BuildValue("s", returnstring);
static PyObject* helloworld(PyObject *self, PyObject *args)
    if (!PyArg_ParseTuple(args, ""))   /* No arguments expected */
        return NULL;
    printf("Hello, world!\n");
    return Py_None;                    /* No return value */

Extending Python

A module is created with the new functions via:

static PyMethodDef newMethods[] =
    {"encrypt", encrypt, METH_VARARGS,
     "Returns an encrypted version of a string."},
    {"helloworld", helloworld, METH_VARARGS,
     "Prints 'Hello, world!'."},
    {NULL, NULL, 0, NULL}
Py_InitModule("mymodule", newMethods);

Python code that is subsequently executed via an embedded interpreter (PyRun_*) can then do:

    import mymodule
    cryptText = mymodule.encrypt('A secret message')

Extending Python

pycave2.c uses embedded Python along with extension functions

It creates a module cave, with the functions:

Extending Python

To make a module loadable from regular (non-embedded) Python, you must build a shared library
(sometimes called a 'DSO' in Unix, or 'DLL' in Windows)

The code must include an init function, which is called when the module is loaded

If the module is named foo, then the init function is initfoo()
For example:

  void initcrypto(void)
      (void) Py_InitModule("crypto", newMethods);

In Unix, compile a DSO like this:

  cc -I/usr/include/python -O -shared -o crypto.so crypto.c

The location of the module may need to be added to your PYTHONPATH environment variable; e.g.:

  setenv PYTHONPATH ~/python


Another way to extend Python is via the ctypes module

ctypes web page

With ctypes, one can access a system library and get pointers to functions within it

These functions are normally only callable from languages like C

ctypes creates Python function objects to wrap them

It also converts between Python & C data types for arguments and return values


import ctypes

libgl = ctypes.cdll.LoadLibrary('/usr/lib/libGL.so')

glMultiTexCoord2dARB = libgl.glMultiTexCoord2dARB
glMultiTexCoord2dARB.argtypes =  [ ctypes.c_uint , ctypes.c_double , ctypes.c_double ]

glGetError = libgl.glGetError
glGetError.argtypes =  [ ]
glGetError.restype = ctypes.c_uint

Creative Commons License
This document is by Dave Pape, and is released under a Creative Commons License.