Note

In the migration of the blog, the code blocks have lose its format. Now the code that you see is not properly indented. I'm sorry about that. I wont delete the post because it has links to interesting information.


One year ago I created a CPython C module. It was a parser that readed a string from a file and take from it some data. It was more an academic exercice than a real need, but I had mixed feelings about the experience: I liked to create a C module because it runned 2x times faster than the optimized and laizy code in Python (is not that much, but the job was pretty simple, and the functions I were using in Python were implemented in C too) and it was funny to do. But the documentation about how to create a C module in Python was messy and most of the examples, broken. So I have decided to write some examples for future reference.

I WILL NOT explain how to do a Python Module from the scratch, there are a lot of information about that out there:

  • Extending Python with C or C++ modules is a basic guide that you can follow for building your first C module.
  • Parsing arguments and building values, very useful when you want to convert Python datatypes to C datatypes.
  • Concrete Objects Layer or how to deal with the received parameters in C code from Python and how to build the return values.
  • Building C and C++ extension with distutils: Python provides a special script for building make files and building your extension. This is the way you compile you extension an then you are able to import the result in the Python interpreter as a module.
  • Are you using Windows? If the answer is Yes: Get the fuck out of my blog.  Nhá, just kidding (or not, who knows?). Here you can find the documentation on how build extensions on Windows.
  • Very good guide with a HelloWorld example of a module. I really recommend it.

Ok, basically I thing that the important information here is: How we read the information sent from Python to the C code? Once you have the information as a C type, you can write you C code as you normaly would do it. After doing the processing of the data you will want to return some information to the Python caller. How to transform C datatypes to Python datatypes? I will show you how to do it by example:.

I have created a module called "example.c" that have three functions that uses strings as input and return a string or integer. Let's see how they work:

EXAMPLE 1:

[c]

static PyObject * string(PyObject self, PyObject args) {
/ EXAMPLE 1
Reading: string
Returning: composed string
Example Input : "hello"
Example Output : "C Function received: hello"
/
const char
str;

// Parse the argument as a string
if (!PyArg_ParseTuple(args, "s", &str))
return NULL;

// Create an array with the first part of the result
char result[256] = {"C Function received: "};

// Copy the received string at the end of the result string
int i = 0, n;
while (result[i] != '\0') { i++; }
for (n = 0; i < 255; n++) {
result[i++] = str[n];
}
result[i] = '\0';

// Create a PyString (PyObject) passing the pointer to the first
// char of our string:
PyObject * result_pyobject = PyString_FromString(result);

// Return the PyObject
return result_pyobject;
}
[/c]

EXAMPLE 2:

[c]

static PyObject * string_reverse(PyObject self, PyObject args) {
/ EXAMPLE 2
Reading: string
Returning: the same string but reversed
Example Input : "hello"
Example Output : "C Function received: hello"
*/

char *str;

// Parse the argument as string
if (!PyArg_ParseTuple(args, "s", &str))
return NULL;

// Reverse the string
int i;
char tmp_char;
// The -1 is because we want to ignore the \0 characer
size_t str_len = strlen(str) - 1;
for (i = 0; i < str_len/2; i++) {
tmp_char = str[i];
str[i] = str[str_len - i];
str[str_len - i] = tmp_char;
}

// Generate the PyObject from our reversed string
PyObject * result_pyobject = PyString_FromString(str);

// Return the result to the Python code return result_pyobject; } [/c] **EXAMPLE 3**: [c] static PyObject * string_len(PyObject *self, PyObject *args) { /* EXAMPLE 3 * Reading: String * Returning: The number of characters that the string have * Example Input : "hello" * Example Output : 5 * */ // Read the givent string char *str; if (!PyArg_ParseTuple(args, "s", &str)) return NULL; // Yep, I'm using str_len. Why shouldn't I? This is just an example! size_t str_len = strlen(str); // Generate the PyObject from a size_t variable // I could used PyInt_FromString, PyInt_FromLong or PyInt_FromSsize_t // depending on the input datatype. Check the documentation for further // information PyObject * result = PyInt_FromSize_t(str_len); return result; } [/c] Ok, these examples are just snipets of the code, but I think you can use them for do whatever you want. I promise I will publish all the source code on github or bitbucket with the full examples and the instructions of how to run everything. If you want the code just right now, leave a comment and I will send it to you or I will publish the code I already have. And I promise to explain how to use **lists, tuples and dictionaries** in C modules in a future post. Just stay tuned!