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)
    {
    Py_Initialize();
    PyRun_SimpleString("import time\n"
                       "print 'time =', time.time()\n");
    Py_Finalize();
    }

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:

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

    Py_Finalize();





Embedding Python

Functions to use:

Py_Initialize()
Call once, before any other Python functions
Py_Finalize()
Call before exiting program

PyRun_SimpleString(string)
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");
    Py_INCREF(Py_None);
    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')
    
    mymodule.helloworld()





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





ctypes

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

Example:

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.