python bindings overview
DESCRIPTION
Python always got a good relation with the C language, through its syntax affinity or with its own API integrated with C. Presentation's goal is to describe and compare several ways of doing bindings in C/C++ for Python which allow to augment Python features through speed improvements or giving access to a large ecosystem of C/C++ (or other) libs. Following is presented : Python C API, ctypes, SWIG, Cython speaking about qualities and weak points.TRANSCRIPT
PYTHON BINDINGS OVERVIEWRudá Moura : [email protected]
Sébastien Tandel : [email protected]
PYTHON C APIPythonBrasil[5]
Caxias do Sul, RS - Brazil
3
PYTHON C API : PHILOSOPHY
Everything is a PyObject* Public symbols with Py prefix Private symbols with _Py prefix Objects are stored in memory heap
It’s you job to count the references Py_INCREF & Py_DECREF Yeah, that’s sucks!
There are functions to convert C data types to Python C data types and back PyArg_ParseTuple() Py_BuildValue()
PYTHON C API
A wrapper around two readline functions: readline - return a malloced string add_history - add a (const) string to the history
char *readline(const char *); int add_history(const char *);
PYTHON C API
readline()#include <Python.h>#include <readline/readline.h>PyObject *fn_readline(PyObject *self, PyObject *args){ char *prompt; char *line; PyObject *o; if (!PyArg_ParseTuple(args, "s", &prompt)) return NULL; line = readline(prompt); o = Py_BuildValue("s", line); free(line); return o;}
PYTHON C API
add_history()
PyObject *fn_add_history(PyObject *self, PyObject *args){ char *line; int status; PyObject *o;
if (!PyArg_ParseTuple(args, "s", &line)) return NULL; status = add_history(line); o = Py_BuildValue("i", status); return o;}
And if I want to return None? Py_INCREF(Py_None); return Py_None;
PYTHON C API
Registering functions and modules
static PyMethodDefmethods[] = { {"readline", fn_readline, METH_VARARGS, NULL}, {"add_history", fn_add_history, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL}};
PyMODINIT_FUNCinitreadline(void){ (void) Py_InitModule("readline", methods);}
PYTHON C API
Compiling...
$ gcc -dynamiclib -I/usr/include/python2.5 -lpython -lreadline mod_readline.c -o readline.so
Or you can use distutils / setup.py
PYTHON C API
The goods Strong C/C++ and Python integration The best performance possible Full Python data types support
The bads It’s hard work, only good for masochists You’re supposed to be good in C Reference counts nightmare
PYTHON C API : SUMMARY
Learning Curve
Pythonic
C
C++
Others languages
Exceptions handling
SWIGSimplified Wrapper and Interface Generator
SWIG : PHILOSOPHY
Everything is defined in the interface file Module name Literal #include or source code Define What symbols to export
The swig compiler translates the interface file into C source code
SWIG
The interface file
// readline.i
%module readline
%{#include <readline/readline.h>%}
char *readline(const char *);int add_history(const char *);
SWIG
Compiling...
$ swig -python readline.i $ gcc -c readline_wrap.c -I/usr/include/python2.5 $ gcc -dynamiclib readline_wrap.o -lpython -lreadline -o _readline.so
Or you can use distutils / setup.py
SWIG
The goods Full bindings process automatization Strong C++ support (class, template, exception) Not only for Python! Support for Perl, Ruby and others It’s mature (since 1995)
The bads The C file created is not for human consum Callbacks and double references are not easy
SWIG : SUMMARY
Learning Curve
Pythonic
C
C++
Others languages
Exceptions handling
CTYPES
CTYPES : PHILOSOPHY
Ctypes is a dlopen-like for Python
The basic steps : Obtain a handle of a library Use this handle to access library’s functions
from ctypes import cdlllibc_h = cdll.LoadLibrary(“libc.so.6”)libc_h.mkdir(“python-mkdir-test”)
CTYPES
OK, it’s a dlopen-like, and?
libc_h.mkdir(“python-mkdir-test”)
It’s a Python string!
Transparent conversion for these types : None, integers, long, byte strings and unicode
strings
CTYPES
What if I want specific C types?
c_int, c_long, c_char, c_short, c_ulong, …
i = c_int(10)print i.value()10
CTYPES
Functions return values? By default, assumed to be int
from ctypes import cdll, c_char_p
lr = cdll.LoadLibrary("libreadline.dylib")
while True: line = lr.readline(“C:\>")
c_line = c_char_p(line) if not c_line.value: break
CTYPES
Return value as input for another C function?
from ctypes import cdll, c_char_p
lr = cdll.LoadLibrary("libreadline.dylib")
while True: line = lr.readline(“C:\>") c_line = c_char_p(line) if not c_line.value: break lr.add_history(c_line.value) # or lr.add_history(c_line) # or lr.add_history(line)
CTYPES
Is there a way to simplify a bit?
from ctypes import cdll, c_char_p
lr = cdll.LoadLibrary("libreadline.dylib")lr.readline.restype = c_char_p
while True: line = lr.readline("c:>") if not line: break lr.add_history(line)
You can define types for arguments too with .argtypes !
CTYPES
Possible to access structures returned by C functions
Possible to define arrays … but with a fixed length!
Possible to create callback written in Python called by C lib.
On windows, check the number of parameters passed to a function.
Part of Python 2.5
CTYPES : SUMMARY
Learning Curve
Pythonic
C
C++
Others languages
Exceptions handling
CYTHON
CYTHON : PHILOSOPHY
Cython is an extension of Python language
Three simple steps :1. Write “python”2. Compile the module it with C compiler3. Import the package in your python code
CYTHON
Compiling a module => setuptools
print “hello world!”
setup.py
from distutils.core import setupfrom distutils.extension import Extensionfrom Cython.Distutils import build_ext
setup( cmdclass = {'build_ext': build_ext}, ext_modules = [Extension(”hello", [”hello.pyx"])])
CYTHON
cdef extern from "readline/readline.h": char* readline(char*) int add_history(char*)
def readline_loop(): while True: line = readline("c:\>”) if not line: break
add_history(line)
CYTHON
setup.py
from distutils.core import setupfrom distutils.extension import Extensionfrom Cython.Distutils import build_ext
setup( cmdclass = {'build_ext': build_ext}, ext_modules = [Extension(‘readlineloop’,
[‘readline-loop.pyx’], libraries = [‘readline’])]
)
CYTHON
Last details :
Can access C structures Possible to define callbacks Check on number of args Possible to wrap C++ classes! Handle exceptions! Can be used to optimize your code
need to learn a bit more
CYTHON
Some limitations :
No support to yield No nested def No globals(), locals() Class / func can’t be placed inside control
structures
CYTHON : SUMMARY
Learning Curve
Pythonic
C
C++
Others languages
Exceptions handling
CONCLUSIONS
C API SWIG Ctypes Cython
Learning Curve
Pythonic
C
C++
Others languages
Exceptions handling