-
Notifications
You must be signed in to change notification settings - Fork 4
PyBCCpython
= Using the C/Python Interface =
The standard implementation of Python, CPython (that's what you're all using), contains a C API allowing programmers to communicate between C and Python. This allows us to either ''extend'' Python with new functionality, or ''embed'' Python into C applications. In this case, we'll be talking about ''extending''.
Why would you want to write Python in C? There are two main reasons: first, you may want to add a feature to Python that you can't implement from inside Python, but there's a C library that allows it. Second, you may have something written in Python that's simply not fast enough. In this case, other options, like Cython, exist, but experienced C programmers may be more comfortable using the Python C API.
{{{ #!div style="border: 1px solid #d7d7d7; margin: 1em 1.75em; padding: .25em; overflow: auto;" '''Aside: Reference Counting''[[BR]]
C doesn't support automatic reference counting. This means we're forced to manually manage the reference counts of objects in Python. To do this, we use the functions {{{Py_INCREF}}} and {{{Py_DECREF}}}. You should also be aware of which functions ''change'' the reference count (most of them) and which ones "steal" a reference. The Python C API [http://docs.python.org/c-api/index.html documentation] will tell you all the functions that steal references. }}}
== The Anatomy of an Extension Module ==
{{{ #!CodeExample #!c #include <Python.h> #include <stdio.h>
static PyObject * hello_world(PyObject *self, PyObject *args) {
printf("Hello, world!n"); Py_RETURN_NONE;
}
- static PyMethodDef methods[] = {
- {"hello_world", hello_world, METH_VARARGS, "Greet the world!"}, {NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC inithello(void) {
PyObject *m; m = Py_InitModule("hello", methods); if (m == NULL)
return;
The first step is #including Python.h, which pulls in all the necessary definitions to use the Python C API. We can then start defining functions in our extension module. There are several types of functions, but the most notable are function with variable number of arguments ({{{METH_VARARGS}}}), or functions with keyword arguments ({{{METH_KEYWORDS}}}). The C signature for all varargs functions is:
{{{ #!CodeExample #!c static PyObject * hello_world(PyObject *self, PyObject *args) }}}
In the case of methods, {{{self}}} refers to the instance on which we are calling the method, and in the case of free/class functions, {{{self}}} refers to the class or module. Note that our function is declared {{{static}}}. While not strictly necessary, this helps to avoid name collisions when Python loads your extension module. The only non-static function in your C code should be your init function, which we'll discuss below.
You'll also notice that we end our function with {{{Py_RETURN_NONE;}}}. You should ''always'' return something from your C functions, even if it's {{{None}}}. Returning {{{NULL}}} or {{{0}}} signifies that an error occurred.
Later, we create an array of {{{PyMethodDef}}} objects, which are what actually link our C functions to Python. For our {{{hello_world}}} function, we write:
{{{ #!CodeExample #!c {"hello_world", hello_world, METH_VARARGS, "Greet the world!"} }}}
This gives, in order, the Python name of the function, the C function to use, the function's argument type, and the function's docstring. Once we've defined all the functions we want, we end the array with a {{{PyMethodDef}}} full of {{{NULL}}}s as a sentinel.
Finally, we create a function to initialize our module. The function must be named "init<modulename>" so that Python can find it. Inside the function, we call {{{Py_InitModule("hello", methods)}}}, which initializes a Python module named {{{hello}}} with the methods listed inside {{{methods}}}. We're done!
== Building an Extension Module ==
But wait... how do we actually compile our extension module? Are we going to have to figure out a bunch of obscure compiler commands that vary across platforms? No! Python extension modules, like other Python modules, can be built with distutils. Below, we see a simple {{{setup.py}}} file that will compile our extension module:
{{{ #!CodeExample #!python from distutils.core import setup, Extension
- hello = Extension('hello',
- sources = ['hello.c'] )
- setup(name = 'Hello',
- version = '1.0', description = 'C/Python example', author = 'Python Bootcamp', author_email = '[email protected]', ext_modules = [hello], )
}}}
== Arguments ==
Our function above isn't very useful. It doesn't take any arguments and it doesn't return anything either. Let's make a (slightly) more useful function that accepts some arguments:
{{{ #!CodeExample #!c static PyObject * snowclone(PyObject *self, PyObject *args) {
int num_snow; int num_other; char *people; char *other;
- if( PyArg_ParseTuple(args, "isis", &num_snow, &people, &num_other, &other) == 0)
- return NULL;
- printf("If Eskimos have %d words for snow, %s surely have %d words for "
- "%s.n", num_snow, people, num_other, other);
Py_RETURN_NONE;
The key here is {{{PyArg_ParseTuple}}}. When you call a C function from Python, it builds a tuple and passes it to C. We can then extract the values in this tuple using a format string, in our case {{{"isis"}}}. Each character represents one argument of a particular type; {{{"i"}}} is an {{{int}}}, and {{{"s"}}} is a string. There are a wide variety of types that you can specify. Some other important ones are {{{"d"}}} for a {{{double}}} (Python {{{float}}}) and {{{"O"}}} for any Python object.
After specifying the format string, we pass in the addresses of our C variables, one per argument. Python will convert its Python objects to the appropriate C data type (if possible) and fill in the values. If Python can't parse the tuple, {{{PyArg_ParseTuple}}} will return 0, and we can return with an error.
== Keyword Arguments ==
Expanding upon this, we can create a C function that accepts keyword arguments. This is especially useful when you have many arguments, or multiple optional arguments.
{{{ #!CodeExample #!c static PyObject * madlib(PyObject *self, PyObject *args, PyObject *kw) {
- static char *kwlist[] = {"name_of_person", "place", "past_tense_verb",
- "noun", 0};
char *name; char *place; char *verb; char *noun;
- if( PyArg_ParseTupleAndKeywords(args, kw, "ssss", kwlist, &name, &place,
&verb, &noun) == 0)return NULL;
printf("One day, %s went to %s and %s your %s.n", name, place, verb, noun); Py_RETURN_NONE;
The key difference is that we now use {{{PyArg_ParseTupleAndKeywords}}} and pass in an array of strings called {{{kwlist}}}. As you'd expect, {{{kwlist}}} is a list of names for our keyword arguments.
== Return Values ==
Accepting values to our C functions is nice, but what about returning them? Well, since all our functions are defined as returning a {{{PyObject *}}} (the generic "Python object" type), we just need to create (or find) a Python object to return. Most basic types have a simple function for creating a Python object from a C variable, like so:
{{{ #!CodeExample #!c static PyObject * the_answer(PyObject *self, PyObject *args) {
return PyInt_FromLong(42);
For more complicated values (or if you merely prefer the syntax), we can use {{{Py_BuildValue}}} instead:
{{{ #!CodeExample #!c static PyObject * modf(PyObject *self, PyObject *args) {
double x, f, i; PyArg_ParseTuple(args, "d", &x); f = modf(x, &i); return Py_BuildValue("(dd)", i, f);
== Above and Beyond ==
Obviously, there are many things we haven't covered, such as creating classes. The Python C API allows access to every feature available in Python, though it's oftentimes quite verbose. To read more about how to use the Python C API, consult the official [http://docs.python.org/extending/ documentation].