Python Mypyc Compilation — Core Concepts

What mypyc is

Mypyc is a compiler that transforms type-annotated Python modules into C extension modules. It is built on top of mypy (the static type checker) and uses the same type analysis infrastructure. The more precise your type annotations, the faster the compiled code runs.

The output is a standard .so (Linux/macOS) or .pyd (Windows) file that Python imports like any other C extension. Your module’s public API stays identical — callers cannot tell it was compiled.

How it works

# fib.py — standard typed Python
def fib(n: int) -> int:
    if n <= 1:
        return n
    a, b = 0, 1
    for _ in range(n - 1):
        a, b = b, a + b
    return b

Compile it:

# Install mypyc (ships with mypy)
pip install mypy

# Compile the module
mypyc fib.py
# Produces: fib.cpython-311-x86_64-linux-gnu.so

Now import fib loads the compiled version automatically. The function fib(40) runs 3-5x faster because mypyc generates C code that uses native long arithmetic instead of Python object operations.

Why type hints matter for speed

In standard Python, every operation goes through a generic dispatch:

# Python: a + b
1. What type is a? (check at runtime)
2. What type is b? (check at runtime)  
3. Does a have __add__? (lookup at runtime)
4. Call a.__add__(b) (dispatch at runtime)
5. Handle TypeError if incompatible (check at runtime)

With type annotations, mypyc knows the types at compile time and generates direct C operations:

# Mypyc compiled: a + b (both int)
1. Add two C longs (single CPU instruction)
2. Check for overflow (branch prediction handles this)

This is where the speedup comes from — eliminating the type-checking and dispatch overhead that dominates tight loops and computation-heavy code.

What compiles well

Mypyc excels with specific code patterns:

PatternSpeedupWhy
Integer/float arithmetic loops3-5xNative C arithmetic
Class-heavy code with typed attributes2-4xDirect struct access vs dict lookup
String operations1.5-3xAvoids PyObject overhead
Function calls between compiled modules2-4xDirect C function calls
Code using list[int], dict[str, int]2-3xSpecialized container operations

Code that does not benefit much:

  • I/O-bound operations (networking, file reads)
  • Code calling untyped libraries extensively
  • Heavily dynamic code (eval, exec, monkey-patching)

Compiling a package

For multi-file packages, use setup.py or pyproject.toml:

# setup.py
from setuptools import setup
from mypyc.build import mypycify

setup(
    name="mypackage",
    ext_modules=mypycify([
        "mypackage/__init__.py",
        "mypackage/core.py",
        "mypackage/utils.py",
    ]),
)
pip install -e .

Only compile the performance-critical modules. Modules with heavy dynamic behavior can remain as regular Python.

Limitations to know

Mypyc restricts some Python dynamism in compiled modules:

  • No monkey-patching compiled classes or functions from outside.
  • No dynamic attribute addition to instances of compiled classes (they use fixed slots).
  • Limited metaclass support — custom metaclasses may not work.
  • No *args/**kwargs in some contexts — typed signatures are preferred.

These restrictions exist because mypyc generates fixed C structs for classes and direct function calls. The dynamic features Python allows would break these assumptions.

Mypyc vs Cython

AspectMypycCython
Input languageStandard Python + type hintsCython language (Python superset)
Learning curveLow (just add types)Medium (new syntax for C types)
Maximum speedup2-5x typical10-100x with full C typing
Build integrationpip/setuptoolspip/setuptools
Type systemPython’s typing moduleOwn type system + Python types

Mypyc is the better choice when you want moderate speedups with minimal code changes. Cython is better when you need maximum performance and are willing to write more specialized code.

Common misconception

“Mypyc is just mypy with extra steps — type checking already makes code faster.”

Type checking with mypy does not affect runtime performance at all. Mypy only analyzes your code statically and reports errors. Mypyc takes the extra step of actually using that type information to generate compiled C code. Same type annotations, completely different outcome — one catches bugs, the other makes code faster.

One thing to remember: Mypyc rewards you for good typing practices — the type annotations you already write for code quality become performance optimizations when compiled, giving you 2-5x speedups on CPU-bound Python.

pythonmypyccompilationtype-hintsperformance

See Also

  • Python Appimage Distribution An AppImage is like a portable app on a USB stick — download one file, double-click it, and your Python program runs on any Linux computer without installing anything.
  • Python Briefcase Native Apps Imagine a travel agent who repacks your suitcase for each country's customs — Briefcase converts your Python app into proper native packages for every platform.
  • Python Flatpak Packaging Flatpak wraps your Python app in a safe bubble that works on every Linux system — like a snow globe that keeps your program perfect inside.
  • Python Nuitka Compilation What if your Python code could run as fast as a race car instead of a bicycle? Nuitka translates Python into C to make that happen.
  • Python Pex Executables Imagine zipping your entire Python project into a single magic file that runs anywhere Python lives — that's what PEX does.