How to write Python C++ extensions under Windows
Writing Python C++ extensions is very simple and it will help you understand the language a little better.

Development Cluj-Napoca, March 23, 2016, by Sebastian Brestin
Estimated reading time:

Writing Python C++ extensions is very simple and it will help you understand the language a little better.

With the purpose in mind of just showing you the mechanics behind building C++ extensions you will create a very basic math library. For this task I will use Visual Studio 2015 Community Edition and Python 2.7.10.

1. Create an empty project. Since this will be a simple math library you will name the project math_demo.




2. Go to Property Pages -> General and set the Target Name, Target Extension and Configuration Type




3. Go to Property Pages -> VC++ Directories and set the include and lib directory




4. Now you are all set up to write down the code. Create a source file.




5. Your first math function will be a random function that will simply invoke C++ rand().

static PyObject* random(PyObject* self, PyObject* args)
{
    /* initialize random seed: */
    srand(time(NULL));
    int random = rand() % 10;
    PyObject * python_val = Py_BuildValue("i", random);
    return python_val;
}


As you can see PyObject is not recognized. In order to fix this issue you will have to #include <Python.h>.

You can read more about PyObject here.

Just to summarize:
 
“All object types are extensions of this type. This is a type which contains the information Python needs to treat a pointer to an object as an object.”

Basically it is like object type from Python.

The random function has to respect PyCFunction definition. You can read about this at the same link from above. But in a few words it has to return PyObject and it has to support two arguments of the type PyObject. The first one in this case is the module and the second one contains all the arguments from the call stack.

6. Now that you have your function you need to export it. The following code snippet will show you how.

PyMODINIT_FUNC initmy_math(void)
{
    static PyMethodDef methods[] = {
        { "random", random, METH_NOARGS,
        "Generate random number betweeen 0-9" },
        { NULL, NULL, 0, NULL }
    };

    PyObject *m = Py_InitModule("my_math", methods);
}


So what is going on here? You declare an entry point initname that will be invoked when the module is imported. Basically just as __init__.py works. Using the PyMethodDef structure you then specify the details about the functions that that you want to export.
As you can see, they are the name, the reference, the way it will be invoked and a description.

As a last step you call Py_InitModule, passing it the module name and the structure that contains the functions information.

7. Now we can build the project and test our code in the python console.



For the second method you’ll make an addition function named add, that adds two integers together.

static PyObject* add(PyObject* self, PyObject* args)
{
    int x = 0, y = 0, s = 0;
    PyArg_ParseTuple(args, "ii", &x, &y);
    s = x + y;
    PyObject * python_val = Py_BuildValue("i", s);
    return python_val;
}


You have the same function definition, but this time it receives arguments and you have to parse them, add them and return a python specific result.

For details about parsing you can read this

Now you only have to add your new method to the module. But this time you have to specify that it will receive arguments.

PyMODINIT_FUNC initmath_demo(void)
{
    static PyMethodDef methods[] = {
        { "random", random, METH_NOARGS,
        "Generate random number betweeen 0-9" },
        { "add", add, METH_VARARGS, "Add two integers" },
        { NULL, NULL, 0, NULL }
    };

        PyObject *m = Py_InitModule("math_demo", methods);
}



9. Build and test from Python console.



Building Python extensions in C++ is not that complicated. You can always check their awesome documentation which explains all in depth.

I hope you enjoyed this short tutorial. Stay tuned for more Pythonic learnings! 
 
Image of Sebastian Brestin
About the author
Passionate about tech start-ups & creative writing.

20 Comments


  1. Ionel Cristian Mărieș said on:

    Note that Python 2.7 requires the older Visual C++ 2008 (9.0) (that's what the "MSC v.1500") means. For very simple things the VS 2015 edition will work but there will be problems with the CRT, as every version of the C++ compiler comes with a different and incompatible CRT. In VS 2015 they introduced UCRT, which solves this problem but only forwards, not backwards. You can read more about it here: http://stevedower.id.au/blog/building-for-python-3-5/ There might be a way to make VS 2015 use the older compiler (with matching CRT) or older CRT but I don't know how. Python 3.5 and older are build with VS 2015 (and UCRT), thus less restrictions on compiler version (needs to only be at least 2015).

    Reply

Leave a Comment