Skip to content

Cython

Overview

Cython compiles Python to C:

  • Mixed Python/C: Write Python that compiles to C
  • Type declarations: Hint types for optimization
  • Performance: 10-100x speedup compared to pure Python
  • Ease of use: Easier than manual C extensions

Basic Cython

Simple Cython Function

# fib.pyx
def fibonacci(int n):
 """Compute Fibonacci - typed for speed."""
 if n <= 1:
 return n
 return fibonacci(n-1) + fibonacci(n-2)

Compile and use:

# setup.py
from setuptools import setup
from Cython.Build import cythonize

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

# Build

# Use:
from fib import fibonacci
print(fibonacci(35)) # Instant!

Type Declarations for Speed

# fast_math.pyx
cdef double square(double x):
 """C function - very fast."""
 return x * x

cdef double sum_squares(double[:] arr):
 """Use typed memoryview for array speed."""
 cdef double total = 0.0
 cdef int i
 for i in range(arr.shape[0]):
 total += square(arr[i])
 return total

def sum_squares_py(arr):
 """Python wrapper."""
 cdef double[:] view = arr
 return sum_squares(view)

Typed Memory Views

Array Optimization

# array_ops.pyx
cdef double[:,::1] matrix_multiply(double[:,::1] A, double[:,::1] B):
 """Typed matrix multiply."""
 cdef int m = A.shape[0]
 cdef int n = B.shape[1]
 cdef int k = A.shape[1]

 cdef double[:,::1] C = zeros((m, n))

 cdef int i, j, l
 for i in range(m):
 for j in range(n):
 for l in range(k):
 C[i, j] += A[i, l] * B[l, j]

 return C

Interfacing with C

Calling C Functions

# math_interface.pyx
cdef extern from "math.h":
 double sin(double x)
 double cos(double x)

def py_sin(double x):
 return sin(x)

def py_cos(double x):
 return cos(x)

Performance Example

Pure Python vs Cython

# Pure Python
def compute_python(n):
 total = 0
 for i in range(n):
 total += i ** 0.5
 return total

# Time
# Cython
cdef compute_cython(long n):
 cdef double total = 0.0
 cdef long i
 for i in range(n):
 total += i ** 0.5
 return total

# Time

-

Real-World ML Example

Custom Loss in Cython

# custom_loss.pyx
import numpy as np
cimport numpy as np
cdef extern from "math.h":
 double exp(double x)

def huber_loss(double[::1] predictions, double[::1] targets, double delta):
 """Huber loss in Cython."""
 cdef int n = predictions.shape[0]
 cdef double loss = 0.0
 cdef double error
 cdef int i

 for i in range(n):
 error = predictions[i] - targets[i]
 if abs(error) <= delta:
 loss += 0.5 * error * error
 else:
 loss += delta * (abs(error) - 0.5 * delta)

 return loss / n

Summary: When to Use Cython

Scenario Use Cython
Tight loops with math
Array operations
I/O-bound code (threading better)
Numerical compute
Complex logic ~ (maybe)

-

  • [03 Jit Compilation & Optimization](/05-py3/09-bytecode-and-execution/(03-jit-compilation-optimization/) - JIT as alternative
  • 00 Readme - Performance patterns
  • [01 Ctypes & Cffi](/05-py3/04-c-extensions-and-ffi/(01-ctypes-cffi/) - Other FFI approaches