Getting started

Here you will learn some basic things you need to know to get started with mypyc.

Prerequisites

You need a Python C extension development environment. The way to set this up depends on your operating system.

macOS

Install Xcode command line tools:

$ xcode-select --install

Linux

You need a C compiler and CPython headers and libraries. The specifics of how to install these varies by distribution. Here are instructions for Ubuntu 18.04, for example:

$ sudo apt install python3-dev

Windows

From Build Tools for Visual Studio 2022, install MSVC C++ build tools for your architecture and a Windows SDK. (latest versions recommended)

Installation

Mypyc is shipped as part of the mypy distribution. Install mypy like this (you need Python 3.8 or later):

$ python3 -m pip install -U 'mypy[mypyc]'

On some systems you need to use this instead:

$ python -m pip install -U 'mypy[mypyc]'

Example program

Let’s start with a classic micro-benchmark, recursive fibonacci. Save this file as fib.py:

import time

def fib(n: int) -> int:
    if n <= 1:
        return n
    else:
        return fib(n - 2) + fib(n - 1)

t0 = time.time()
fib(32)
print(time.time() - t0)

Note that we gave the fib function a type annotation. Without it, performance won’t be as impressive after compilation.

Note

Mypy documentation is a good introduction if you are new to type annotations or mypy. Mypyc uses mypy to perform type checking and type inference, so some familiarity with mypy is very useful.

Compiling and running

We can run fib.py as a regular, interpreted program using CPython:

$ python3 fib.py
0.4125328063964844

It took about 0.41s to run on my computer.

Run mypyc to compile the program to a binary C extension:

$ mypyc fib.py

This will generate a C extension for fib in the current working directory. For example, on a Linux system the generated file may be called fib.cpython-37m-x86_64-linux-gnu.so.

Since C extensions can’t be run as programs, use python3 -c to run the compiled module as a program:

$ python3 -c "import fib"
0.04097270965576172

After compilation, the program is about 10x faster. Nice!

Note

__name__ in fib.py would now be "fib", not "__main__".

You can also pass most mypy command line options to mypyc.

Deleting compiled binary

You can manually delete the C extension to get back to an interpreted version (this example works on Linux):

$ rm fib.*.so

Using setup.py

You can also use setup.py to compile modules using mypyc. Here is an example setup.py file:

from setuptools import setup

from mypyc.build import mypycify

setup(
    name='mylib',
    packages=['mylib'],
    ext_modules=mypycify([
        'mylib/__init__.py',
        'mylib/mod.py',
    ]),
)

We used mypycify(...) to specify which files to compile using mypyc. Your setup.py can include additional Python files outside mypycify(...) that won’t be compiled.

Now you can build a wheel (.whl) file for the package:

python3 setup.py bdist_wheel

The wheel is created under dist/.

You can also compile the C extensions in-place, in the current directory (similar to using mypyc to compile modules):

python3 setup.py build_ext --inplace

You can include most mypy command line options in the list of arguments passed to mypycify(). For example, here we use the --disallow-untyped-defs flag to require that all functions have type annotations:

...
setup(
    name='frobnicate',
    packages=['frobnicate'],
    ext_modules=mypycify([
        '--disallow-untyped-defs',  # Pass a mypy flag
        'frobnicate.py',
    ]),
)

Next steps

You can sometimes get good results by just annotating your code and compiling it. If this isn’t providing meaningful performance gains, if you have trouble getting your code to work under mypyc, or if you want to optimize your code for maximum performance, you should read the rest of the documentation in some detail.

Here are some specific recommendations, or you can just read the documentation in order: