Reader small image

You're reading from  Learning Cython Programming (Second Edition) - Second Edition

Product typeBook
Published inFeb 2016
Reading LevelBeginner
PublisherPackt
ISBN-139781783551675
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Philip Herron
Philip Herron
author image
Philip Herron

Philip Herron is a developer who focuses his passion toward compilers and virtual machine implementations. When he was first accepted to Google Summer of Code 2010, he used inspiration from Paul Biggar's PhD on the optimization of dynamic languages to develop a proof of the concept GCC frontend to compile Python. This project sparked his deep interest in how Python works. After completing a consecutive year on the same project in 2011, Philip applied to Cython under the Python foundation to gain a deeper appreciation of the standard Python implementation. Through this he started leveraging the advantages of Python to control the logic in systems or even add more high-level interfaces, such as embedding Flask web servers in a REST API to a system-level piece of software, without writing any C code. Philip currently works as a software consultant for Instil Software based in Northern Ireland. He develops mobile applications with embedded native code for video streaming. Instil has given him a lot of support in becoming a better engineer. He has written several tutorials for the UK-based Linux Format magazine on Python and loves to share his passion for the Python programming language.
Read more about Philip Herron

Right arrow

Getting started – Hello World


As you will see when running the Hello World program, Cython generates native Python modules. Therefore, running any Cython code, you will reference it via a module import in Python. Let's build the module:

$ cd cython-book/chapter1/helloworld
$ make

You should now have created helloworld.so! This is a Cython module of the same name as the Cython source code file. While in the same directory of the shared object module, you can invoke this code by running a respective Python import:

$ python
Python 2.7.3 (default, Aug  1 2012, 05:16:07)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import helloworld
Hello World from cython!

As you can see by opening helloworld.pyx, it looks just like a normal Python Hello World application, but as previously stated, Cython generates modules. These modules need a name so that they can be correctly imported by the Python runtime. The Cython compiler simply uses the name of the source code file. It then requires us to compile this to the same shared object name.

Overall, Cython source code files have the .pyx,.pxd, and .pxi extensions. For now, all we care about are the .pyx files; the others are for cimports and includes respectively within a .pyx module file.

The following screenshot depicts the compilation flow required to have a callable native Python module:

I wrote a basic makefile so that you can simply run make to compile these examples. Here's the code to do this manually:

$ cython helloworld.pyx
$ gcc/clang -g -O2 -fpic `python-config --cflags` -c helloworld.c -o helloworld.o
$ gcc/clang -shared -o helloworld.so helloworld.o `python-config –libs`

Using distutils with Cython

You can also compile this HelloWorld example module using Python distutils and cythonize. Open the setup.py along side the Makefile and you can see the alternate way to compile Cython modules:

from distutils.core import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)

Using the cythonize function as part of the ext_modules section will build any specified Cython source into an installable Python module. This will compile helloworld.pyx into the same shared library. This provides the Python practice to distribute native modules as part of distutils.

Calling C functions from Python

We should be careful for clarity when talking about Python and Cython since the syntax is so similar. Let's wrap a simple AddFunction in C and make it callable from Python.

First, open a file called AddFunction.c, and write a simple function in it:

#include <stdio.h>

int AddFunction(int a, int b) {
    printf("look we are within your c code!\n");
    return a + b;
}

This is the C code that we will call—just a simple function to add two integers. Now, let's get Python to call it. Open a file called AddFunction.h, wherein we will declare our prototype:

#ifndef __ADDFUNCTION_H__
#define __ADDFUNCTION_H__

extern int AddFunction (int, int);

#endif //__ADDFUNCTION_H__

We need this so that Cython can see the prototype for the function we want to call. In practice, you will already have your headers in your own project with your prototypes and declarations already available.

Open a file called AddFunction.pyx, and insert the following code in it:

cdef extern from "AddFunction.h":
    cdef int AddFunction(int, int)

Here, we have to declare which code we want to call. The cdef is a keyword signifying that this is from the C code that will be linked in. Now, we need a Python entry point:

def Add(a, b):
     return AddFunction(a, b)

This Add function is a Python callable inside a PyAddFunction module this acts as a wrapper for Python code to be able to call directly into the C code. Again, I have provided a handy makefile to produce the module:

$ cd cython-book/chapter1/ownmodule
$ make
cython -2 PyAddFunction.pyx
gcc -g -O2 -fpic -c PyAddFunction.c -o PyAddFunction.o `python-config --includes`
gcc -g -O2 -fpic -c AddFunction.c -o AddFunction.o
gcc -g -O2 -shared -o PyAddFunction.so AddFunction.o PyAddFunction.o `python-config --libs`

Notice that AddFunction.c is compiled into the same PyAddFunction.so shared object. Now, let's call this AddFunction and check to see if C can add numbers correctly:

$ python
>>> from PyAddFunction import Add
>>> Add(1,2)
look we are within your c code!!
3

Notice that the print statement inside the AddFunction and the final result are printed correctly. Therefore, we know that the control hit the C code and did the calculation in C, and not inside the Python runtime. This is a revelation of what is possible. Python can be cited to be slow in some circumstances. Using this technique makes it possible for Python code to bypass its own runtime and to run in an unsafe context, which is unrestricted by the Python runtime which is much faster.

Type conversion in Cython

Notice that we had to declare a prototype inside the Cython source code PyAddFunction.pyx:

cdef extern from "AddFunction.h":
    cdef int AddFunction(int, int)

It lets the compiler know that there is a function called AddFunction and it takes two ints and returns an int. This is all the information the compiler needs to know beside the host and target operating system's calling convention to call this function safely. Then, we created the Python entry point, which is a Python callable that takes two parameters:

def Add(a, b):
     return AddFunction(a, b)

Inside this entry point, it simply returned the native AddFunction and passed the two Python objects as parameters. This is what makes Cython so powerful. Here, the Cython compiler must inspect the function call and generate code to safely try and convert these Python objects to native C integers. This becomes difficult when precision is taken into account as well as potential overflow, which just so happens to be a major use case since it handles everything so well. Also, remember that this function returns an integer, and Cython also generates code to convert the integer return into a valid Python object.

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support and register to have the files e-mailed directly to you.

Previous PageNext Page
You have been reading a chapter from
Learning Cython Programming (Second Edition) - Second Edition
Published in: Feb 2016Publisher: PacktISBN-13: 9781783551675
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Philip Herron

Philip Herron is a developer who focuses his passion toward compilers and virtual machine implementations. When he was first accepted to Google Summer of Code 2010, he used inspiration from Paul Biggar's PhD on the optimization of dynamic languages to develop a proof of the concept GCC frontend to compile Python. This project sparked his deep interest in how Python works. After completing a consecutive year on the same project in 2011, Philip applied to Cython under the Python foundation to gain a deeper appreciation of the standard Python implementation. Through this he started leveraging the advantages of Python to control the logic in systems or even add more high-level interfaces, such as embedding Flask web servers in a REST API to a system-level piece of software, without writing any C code. Philip currently works as a software consultant for Instil Software based in Northern Ireland. He develops mobile applications with embedded native code for video streaming. Instil has given him a lot of support in becoming a better engineer. He has written several tutorials for the UK-based Linux Format magazine on Python and loves to share his passion for the Python programming language.
Read more about Philip Herron