Python is a reasonably fast language, but it’s not as fast as compiled programs. That’s because CPython, the standard implementation, is interpreted. To be more precise, your Python code is compiled into byte code that is then interpreted. That’s good for learning, as you can run code in the Python REPL and see results immediately rather than having to compile and run. But because Python programs aren’t that fast, developers have created several Python compilers over the years, including IronPython and Jython.

Fast performance isn’t the only reason for compiling; possibly the biggest disadvantage of scripting languages such as Python is that you implicitly provide your source code to customers.

I wanted to compare a few Python compilers on the same platform, especially those that support Python 3.x. In the end, I chose four, all running on Ubuntu Linux: Nuitka, PyPy, Cython and cx_Freeze. (Originally I targeted five, but Pythran didn’t like the benchmark programs I used, so it didn’t make the cut.)

If you’re interested in Python compilers in general, just be aware that there’s a lot of debate and controversy over the “best” ones (just check out this Quora thread). Stack Exchange also offers some nifty discussions about Python, compilers, and the language’s general speediness.

Comparing Python Compilers

Somebody has already done the work of creating a Python benchmark. I opted for PyStone, a translation of a C program by Guido van Rossum, the creator of Python (the C program was itself a translation of an Ada program). I found a converted version by developer Christopher Arndt on GitHub that was capable of testing Python 3. To give a sense of perspective, here’s CPython (i.e., standard Python) performance with Pystone:

Python 2.7.15Rc1 2 : 272,647 pystones/second. Python 3.6.5 : 175,817

As you can see, there’s quite a big difference between Python 2 and 3 (the more Pystones per second, the better). In the following breakdowns, all Python compilers were benchmarked against Python 3.

Nuitka

Although you can follow the instructions on the download page, the following on Ubuntu worked fine for me:

sudo apt install Nuitka

Nuitka also needs a C compiler, so I downloaded clang. You can install it with this:

sudo apt install clang

By default, Nuitka uses gcc, but a parameter lets you use clang, so I tested it with both. The clang compiler is part of the llvm family, and is intended as a modern replacement for gcc. Compiling pystone.py with gcc was as simple as this (first line), or with clang (second line), and with link time optimization for gcc (third line):

nuitka pystone.py nuitka pystone.py --clang nuitka pystone.py --lto

After compiling, which took about 10 seconds, I ran the pystone.exe from the terminal with:

./pystone.exe 500000

I did 500,000 passes:

Size Execution pystones/sec 1. 223.176 Kb 597,000 2. 195,424 Kb 610,000 3. 194.2 kb 600,000

These were the averages over 5 runs. I’d closed down as many processes as I could, but do take the timings with a bit of salt because there was a +/- 5% on timing values.

PyPy

Guido van Rossum once said: “If you want your code to run faster, you should probably just use PyPy.” I downloaded the portable binaries into a folder, and, in the bin folder under that, copied pystone.py. Then I ran it like this:

./pypy3.5 pystone.py

The result was a stunning 1,776,001 pystones per second, almost three times faster than Nuitka.

PyPy uses a just-in-time compiler and does some very clever stuff to achieve its speed. According to reported benchmarks, it is 7.6 times faster than CPython on average. I can easily believe that. The only (slight) disadvantage is that it’s always a little behind Python versions (i.e., up to 2.7.13 (not 2.7.15) and 3.5.3 (not 3.6.5 )).

Producing an exe takes a bit of work. You have to write your Python in a subset called RPython.

Cython

Cython isn’t just a compiler for Python; it’s for a superset of Python that supports interoperability with C/C++. CPython is written in C, so it’s a language that generally mixes well with Python.

Setting things up with Cython is a little bit fiddly. It’s not like Nuitka, which just runs out of the box. First, you have to start with a Python file with a .pyx extension; you run Cython to create a pystone.c file from that:

cython pystone.pyx --embed

Don’t omit the –embed parameter. It adds in main and that is needed. Next, you compile pystone.c with this lovely line:

gcc $(python3-config --includes) pystone.c -lpython3.6m -o pystone.exe

If you get any errors, such as ‘can’t find the -lpython version,’ it could be the result of your version of Python. To see what version is installed, run this command:

pkg-config --cflags python3

After all that, Cython only gave 228,527 pystones/sec. However, Cython needs you to do a bit of work specifying the types of variables. Python is a dynamic language, so types aren’t specified; Cython uses static compilation, and using C typed variables lets it produce much better optimized code. (The documentation is quite extensive and required reading.)

Size Execution pystones/sec 1. 219,552 Kb 228,527

cx_freeze

This is a set of scripts and modules for “freezing” Python scripts into executables, and can be found on GitHub.

I installed it and created a folder freeze to manage things in:

sudo pip3 install cx_Freeze --upgrade

One problem I found with the install script was an error missing “lz”. You need to have zlib installed; run this to install it:

sudo apt install zlib1g-dev

After that, the cx_Freeze command took the pystone.py script and created a dist folder containing a lib folder, a 5MB lib file and the pystone application file:

cxfreeze pystone.py --target-dir dist

Size Execution pystones/sec 1. 10,216 174,822

Not the fastest performance, because it’s the same speed as CPython. (Python freezing involves shipping your application in a single file (or folder) with the needed Python elements, rather than compiling; it means the target does not require Python.)

Conclusion

I am in awe of PyPy’s performance. Compilation was very fast, and it produced the results less than a second after I pressed the enter key. If you want an exe, though, I recommend Nuitka; it was a no-fuss compile and runs faster than CPython. Experiment with these Python compilers and see which work best for your particular needs.