Last Updated : 29 Mar, 2019
What is Cython ?It is an optimizing static compiler for both the Python programming language and the extended Cython programming language. It is used to make it easy to write C extensions for Python as easy as Python itself. It comes up with many
helpful features:
To make an extension with Cython is a tricky task to perform. Doing so, one needs to create a collection of wrapper functions. Assuming that the work code shown has been compiled into a C library called
libwork. The code below will create a file named
csample.pxd
.
Code #1 : Python3 1==
# cwork.pxd
#
# Declarations of "external" C
# functions and structures
cdef extern from "work.h":
int gcd(int, int)
int divide(int, int, int *)
double avg(double *, int) nogil
ctypedef struct Point:
double x
double y
double distance(Point *, Point *)
In Cython, the code above will work as a C header file. The initial declaration
cdef externfrom
"work.h"
declares the required C header file. Declarations that follow are taken from the header. The name of this file is
cwork.pxd
. Next target is to create a
work.pyx
file which will define wrappers that bridge the Python interpreter to the underlying C code declared in the
cwork.pxd
file.
Code #2 : Python3 1==
# work.pyx
# Import the low-level C declarations
cimport cwork
# Importing functionalities from Python
# and the C stdlib
from cpython.pycapsule cimport *
from libc.stdlib cimport malloc, free
# Wrappers
def gcd(unsigned int x, unsigned int y):
return cwork.gcd(x, y)
def divide(x, y):
cdef int rem
quot = cwork.divide(x, y, &rem)
return quot, rem
def avg(double[:] a):
cdef:
int sz
double result
sz = a.size
with nogil:
result = cwork.avg(<double *> &a[0], sz)
return result
Code #3 : Python3 1==
# Destructor for cleaning up Point objects
cdef del_Point(object obj):
pt = <csample.Point *> PyCapsule_GetPointer(obj, "Point")
free(<void *> pt)
# Create a Point object and return as a capsule
def Point(double x, double y):
cdef csample.Point * p
p = <csample.Point *> malloc(sizeof(csample.Point))
if p == NULL:
raise MemoryError("No memory to make a Point")
p.x = x
p.y = y
return PyCapsule_New(<void *>p, "Point",
<PyCapsule_Destructor>del_Point)
def distance(p1, p2):
pt1 = <csample.Point *> PyCapsule_GetPointer(p1, "Point")
pt2 = <csample.Point *> PyCapsule_GetPointer(p2, "Point")
return csample.distance(pt1, pt2)
Finally, to build the extension module, create a
work.py
file.
Code #4: Python3
# importing libraries
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension('work',
['work.pyx'],
libraries=['work'],
library_dirs=['.'])]
setup(name = 'work extension module',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules)
Code #5 : Building resulting module for experimentation. bash
bash % python3 setup.py build_ext --inplace
running build_ext
cythoning work.pyx to work.c
building 'work' extension
gcc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
-I/usr/local/include/python3.3m -c work.c
-o build/temp.macosx-10.6-x86_64-3.3/work.o
gcc -bundle -undefined dynamic_lookup build/temp.macosx-10.6-x86_64-3.3/work.o
-L. -lwork -o work.so
bash %
Now, we have an extension module
work.so
. Let's see how it works.
Code #6 : Python3
import sample
print ("GCD : ", sample.gcd(12, 8))
print ("\nDivision : ", sample.divide(42,10))
import array
arr = array.array('d',[1,2,3])
print ("\nAverage : ", sample.avg(a)
pt1 = sample.Point(2,3)
pt2 = sample.Point(4,5)
print ("\npt1 : ", pt1)
print ("\npt2 : ", pt2)
print ("\nDistance between the two points : ",
sample.distance(pt1, pt2))
Output :
GCD : 4 Division : (4, 2) Average : 2.0 pt1 : <capsule object "Point" at 0x1005d1e70> pt2 : <capsule object "Point" at 0x1005d1ea0> Distance between the two points : 2.8284271247461903
At a high level, using Cython is modeled after C. The
.pxdfiles merely contain C definitions (similar to
.h
files) and the
.pyx
files contain implementation (similar to a
.c
file). The
cimportstatement is used by Cython to import definitions from a
.pxd
file. This is different than using a normal Python import statement, which would load a regular Python module.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4