A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://www.geeksforgeeks.org/python/cython-to-wrap-existing-c-code/ below:

Cython to Wrap Existing C Code

Cython to Wrap Existing C Code

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 extern

from

"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

.pxd

files merely contain C definitions (similar to

.h

files) and the

.pyx

files contain implementation (similar to a

.c

file). The

cimport

statement 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