Cython is the missing linkbetween the simplicity of Pythonand the speed of C / C++ / Fortran.
Cython is the missing linkbetween the simplicity of Pythonand the speed of C / C++ / Fortran.
Cython is
# file: worker.py class HardWorker(object): u"Almost Sisyphos" def __init__(self, task): self.task = task def work_hard(self, repeat=100): for i in range(repeat): self.task() def add_simple_stuff(): x = 1+1 HardWorker(add_simple_stuff).work_hard()
compile with
$ cython worker.py
translates to ~1500 line .c file (Cython 0.11.3)
... the fastest way to port Python 2 code to Py3 ;-)
Inner functions with closures
def factory(a,b): def closure_function(c): return a+b+c return closure_function
... as usual: great ideas, little time
local/inner classes (~open)
lambda expressions (~easy)
generators (~needs work)
generator expressions (~easy)
with obvious optimisations, e.g.
set( x.a for x in some_list ) == { x.a for x in some_list }
... all certainly on the TODO list for 1.0.
Cython generates very efficient C code:
Cython supports optional type declarations that
To compile Python code (.py) or Cython code (.pyx)
A minimal setup.py script:
from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext ext_modules = [Extension("worker", ["worker.py"])] setup( name = 'stupid little app', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules )
Run with
$ python setup.py build_ext --inplace
Build and import Cython code files (.pyx) on the fly
$ ls worker.pyx $ PYTHONPATH=. python
Python 2.6.2 (r262:71600, Apr 17 2009, 11:29:30) [GCC 4.3.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import pyximport >>> pyximport.install() >>> import worker >>> worker <module 'worker' from '~/.pyxbld/.../worker.so'> >>> worker.HardWorker <class 'worker.HardWorker'> >>> worker.HardWorker(worker.add_simple_stuff).work_hard()
>>> import pyximport >>> pyximport.install(pyimport = True) >>> import shlex [lots of compiler errors from different modules ...] >>> help(shlex)
# file: hw.py def hello_world(): import sys print "Welcome to Python %d.%d!" % sys.version_info[:2] if __name__ == '__main__': hello_world()
# file: hw.py def hello_world(): import sys print "Welcome to Python %d.%d!" % sys.version_info[:2] if __name__ == '__main__': hello_world()
Compile, link and run:
$ cython --embed hw.py # <- embed a main() function $ gcc $CFLAGS -I/usr/include/python2.6 \ -o hw hw.c -lpython2.6 -lpthread -lm -lutil -ldl $ ./hw Welcome to Python 2.6!
# integrate_py.py from math import sin def f(x): return sin(x**2) def integrate_f(a, b, N): dx = (b-a)/N s = 0 for i in range(N): s += f(a+i*dx) return s * dx
Function arguments are easy
Python:
def f(x): return sin(x**2)
Cython:
def f(double x): return sin(x**2)
»cdef« keyword declares
variables with C or builtin types
cdef double dx, s
functions with C signatures
cdef double f(double x): return sin(x**2)
classes as 'builtin' extension types
cdef class MyType: cdef int field
# integrate_py.py from math import sin def f(x): return sin(x**2) def integrate_f(a, b, N): dx = (b-a)/N s = 0 for i in range(N): s += f(a+i*dx) return s * dx
# integrate_cy.pyx cdef extern from "math.h": double sin(double x) cdef double f(double x): return sin(x**2) cpdef double integrate_f(double a, double b, int N): cdef double dx, s cdef int i dx = (b-a)/N s = 0 for i in range(N): s += f(a+i*dx) return s * dx
# integrate_py.py from math import sin def f(x): return sin(x**2) def integrate_f(a, b, N): dx = (b-a)/N s = 0 for i in range(N): s += f(a+i*dx) return s * dx
Python integrate_py.py | Cython integrate_py.pxd |
# integrate_py.py from math import sin def f(x): return sin(x**2) def integrate_f(a, b, N): dx = (b-a)/N s = 0 for i in range(N): s += f(a+i*dx) return s * dx |
# integrate_py.pxd cimport cython cpdef double f(double x) @cython.locals( dx=double, s=double, i=int) cpdef integrate_f( double a, double b, int N) |
# integrate_py.pxd cimport cython cpdef double f(double x): return sin(x**2) cpdef double integrate_f(double a, double b, int N)
# integrate_py.py from math import sin def f(x): return sin(x**2) def integrate_f(a, b, N): dx = (b-a)/N s = 0 for i in range(N): s += f(a+i*dx) return s * dx
from math import sin import cython @cython.locals(x=cython.double) def f(x): return sin(x**2) @cython.locals(a=cython.double, b=cython.double, N=cython.Py_ssize_t, dx=cython.double, s=cython.double, i=cython.Py_ssize_t) def integrate_f(a, b, N): dx = (b-a)/N s = 0 for i in range(N): s += f(a+i*dx) return s * dx
def filter_a(d): return { key : value for key, value in d.iteritems() if 'a' not in value } import string d = { s:s for s in string.ascii_letters } print filter_a(d)
def filter_a(dict d): # <==== return { key : value for key, value in d.iteritems() if 'a' not in value } import string d = { s:s for s in string.ascii_letters } print filter_a(d)
def filter_a(dict d): # <==== return { key : value for key, value in d.iteritems() if 'a' not in value } import string d = { s:s for s in string.ascii_letters } print filter_a(d)
def inplace_invert_2D_buffer( object[unsigned char, 2] image): cdef int i, j for i in range(image.shape[0]): for j in range(image.shape[1]): image[i, j] = 255 - image[i, j]
Cython
C-Extensions in Python
... use it, and join the project!