Before we fully dive into the code examples of Python extensions written in C, here is a huge warning. If you want to extend Python with C, you need to already know both of these languages pretty well. This is especially true for C. Lack of proficiency with it can lead to real disasters due to how easily it can be mishandled.
If you have decided that you need to write C extensions for Python, I assume that you already know the C language at a level that will allow you to fully understand the examples that are presented. Nothing other than Python/C API details will be explained here. This book is about Python and not any other language. If you don't know C at all, you should definitely not try to write your own Python extensions in C until you gain enough experience and skills. Leave it to others and stick with Cython or Pyrex because they are a lot safer from the beginner's perspective. It's because Python/C API, despite being crafted with great care, is definitely not a good introduction to C.
As proposed earlier, we will try to port the fibonacci() function to C and expose it to the Python code as an extension. Let's start with a base implementation that would be analogous to the previous Python example. The bare function without any Python/C API usage could be rough as follows:
long long fibonacci(unsigned int n) { if (n < 2) { return 1; } else { return fibonacci(n - 2) + fibonacci(n - 1); } }
And here is the example of a complete, fully functional extension that exposes this single function in a compiled module:
#include <Python.h> long long fibonacci(unsigned int n) { if (n < 2) { return 1; } else { return fibonacci(n-2) + fibonacci(n-1); } } static PyObject* fibonacci_py(PyObject* self, PyObject* args) { PyObject *result = NULL; long n; if (PyArg_ParseTuple(args, "l", &n)) { result = Py_BuildValue("L", fibonacci((unsigned int)n)); } return result; } static char fibonacci_docs[] = "fibonacci(n): Return nth Fibonacci sequence number " "computed recursively\n"; static PyMethodDef fibonacci_module_methods[] = { {"fibonacci", (PyCFunction)fibonacci_py, METH_VARARGS, fibonacci_docs}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef fibonacci_module_definition = { PyModuleDef_HEAD_INIT, "fibonacci", "Extension module that provides fibonacci sequence function", -1, fibonacci_module_methods }; PyMODINIT_FUNC PyInit_fibonacci(void) { Py_Initialize(); return PyModule_Create(&fibonacci_module_definition); }
The preceding example might be a bit overwhelming at first glance because we had to add four times more code just to make the fibinacci() C function accessible from Python. We will discuss every bit of that code step by step later, so don't worry. But before we do that, let's see how it can be packaged and executed in Python.
The following minimal setuptools configuration for our module needs to use the setuptools.Extension class in order to instruct the interpreter how our extension is compiled:
from setuptools import setup, Extension setup( name='fibonacci', ext_modules=[ Extension('fibonacci', ['fibonacci.c']), ] )
The build process for extensions can be initialized with the setup.py build command, but it will also be automatically performed upon package installation. Same source files you can find in the directory chapter9/fibonacci_c of this book's code package. The following transcript presents the result of the installation in development mode and a simple interactive session where our compiled fibonacci() function is inspected and executed:
$ ls -1ap fibonacci.c setup.py $ python3 -m pip install -e . Obtaining file:///Users/swistakm/dev/Expert-Python-Programming-Third_edition/chapter9 Installing collected packages: fibonacci Running setup.py develop for fibonacci Successfully installed Fibonacci $ ls -1ap build/ fibonacci.c fibonacci.cpython-35m-darwin.so fibonacci.egg-info/ setup.py
$ python3 Python 3.7.2 (default, Feb 12 2019, 00:16:38) [Clang 10.0.0 (clang-1000.11.45.5)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import fibonacci >>> help(fibonacci.fibonacci) Help on built-in function fibonacci in fibonacci: fibonacci.fibonacci = fibonacci(...) fibonacci(n): Return nth Fibonacci sequence number computed recursively >>> [fibonacci.fibonacci(n) for n in range(10)] [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Python/C API is explained in the next section.