What is Cython and what do I use it for?
Cython is an extension of the Python programming language that enables C/C++ and Python interop as well as speeding up Python code. There are three main use cases for Cython:
- Exposing functionality written in Python to native code written in C/C++ – this use case IMO is quite rare. But it is something that Cython enables.
- Exposing functionality written in C/C++ to Python code – this is very useful when we have native libraries in C/C++ that do not have Python bindings but we want to leverage their functionality in Python.
- A higher level language (Python + some extensions) that allows you to produce efficient native code and accessible via Python – basically, write Python code but execute at close to native code speed. This is very useful as you can leverage the ease of use and higher level abstractions provided by Python but get the efficiency of native code during execution.
How does Cython work?
Cython allows you to write Python like code, generates native C (or C++) code from this and compiles it into a Python extension module that can be imported and used in Python like any other Python module.
Here’s a simple example – start by creating CythonHelloWorld.pyx
:
def hello_world():
print('Hello, World!')
Now, we create setup.py
to enable distutils to generate the C file and build the extension from this Cython file:
from distutils.core import setup
from distutils.extension import Extension
import sys
USE_CYTHON = False
if '--use-cython' in sys.argv:
USE_CYTHON = True
sys.argv.remove('--use-cython')
ext = '.pyx' if USE_CYTHON else '.c'
extensions = [
Extension(
name='helloworld',
sources=['CythonHelloWorld'+ext],
language='c',
)
]
if USE_CYTHON:
from Cython.Build import cythonize
extensions = cythonize(extensions)
setup(
name='helloworld',
ext_modules = extensions
)
The above setup.py
file will generate CythonHelloWorld.c
and then build it into a helloworld
Python extension module – the extra complexity here is for distributing this module outside the development environment where the recommended practice is to include the generate .c
or .cpp
file instead of assuming the presence of Cython and having the user generate the file. Use the following command to generate the .c file, compile it into a Python extension and install it in-place:
python setup.py build_ext --inplace --use-cython
Now you can test this by creating run.py
which uses the new extension module:
import helloworld
helloworld.hello_world()
And finally, running the above run.py to verify that it works:
python run.py
Hello, World!
If all you are looking for is using Cython to create faster code that is written in Python like syntax, this is essentially all you need. We will look at the interesting use case of generating a Python accessible wrapper for a C library in a future post.