Using C Codes in Python | Set 1



Let`s discuss the problem of accessing C code from Python. Because it is quite obvious that many of the built-in Python libraries are written in C. Thus, access to C is a very important part of Python`s interoperability with existing libraries. Python provides a rich API for programming in C, but there are many different ways to work with C.

Code # 1: [ work.c ] The C code we`re dealing with.

# include & lt; math.h & gt;

 

int gcd ( int x, int y)

{

int g = y; 

while (x & gt; 0 )

{

g = x; 

x = y % x; 

y = g; 

}

return g; 

}

 

int divide ( int a , int b, int * remainder)

{

int quot = a / b; 

* remainder = a % b; 

return quot; 

}

 

double avg (double * a, int n)

{

int i; 

double total = 0.0

for (i = 0 ; i & lt; n; i + + )

  {

total + = a [i]; 

}

return total / n; 

}

 
typedef struct Point
{

double x, y; 

} Point; 

 

double distance (Point * p1, Point * p2)

{

return hypot (p1 - & gt; x - p2 - & gt; x, p1 - & gt; y - p2 - & gt; y); 

}

The above code has various C programming features.

gcd ()
divide () - returning multiple values, one through a pointer argument
avg () - performing a data reduction across a C array
Point and distance () - involve C structures.

Let`s assume the above code is in a file named work.c and compiled into a library that can be linked to other C code. We now have a number of C functions that have been compiled into a shared library. So, we call functions entirely from Python without the need to write additional C code or use a third-party extension tool.

Using ctypes:
Will play in Python ctypes , but make sure the C code to be converted has been compiled into a shared library that is compatible with the Python interpreter (e.g. same architecture, word size, compiler, etc.).

Also, the libsample.so file has been placed in the same directory as work.py Let`s get to the work.py now.

Code # 2: Python module that wraps the resulting library to access it

# work. py

import ctypes

import os

 
# find file & # 39; libsample .so & # 39; in
# same directory as this file

_ file = `libsample.so`

_ path = os.path.join ( * (os.path.split (__ file __) [: - 1 ] + (_ file,)))

_mod = ctypes.cdll.LoadLibrary (_path)

Code # 3: Code Access

# int gcd (int, int)

gcd = _ mod.gcd

gcd.argtypes = (ctypes.c_int, ctypes.c_int)

gcd.restype = ctypes.c_int

 
# int division (int, int, int *)

_ divide = _ mod.divide

_ divide.argtypes = (ctypes.c_int, ctypes.c_int,

ctypes.POINTER (ctypes .c_int))

 

_ divide.restype = ctypes.c_int

 

def divide (x, y):

rem = ctypes.c_int ()

quot = _ divide (x, y, rem)

return quot, rem.value

 
# void avg (double *, int n)
# Define a special type for the argument & # 39; double * & # 39;

class DoubleArrayType:

  def from_param ( self , param):

 

< p> typename = type (param) .__ name__

 

if hasattr ( self , `from_` + typename):

return getattr ( self , `from_` + typename) (param)

 

elif isinstance (param, ctypes.Array):

  return param

 

else :

raise TypeError ( "Can `t convert% s" % typename)

 

  # Cast from array.array objects

def from_array ( self , param):

i f param.typecode! = `d` :

raise TypeError ( ` must be an array of doubles` )

 

ptr, _ = param.buffer_info ()

return ctypes.cast (ptr, ctypes.POINTER (ctypes.c_double))

 

  # Cast from lists / tuples

def from_list ( self , param):

  val = ((ctypes.c_double) * len (param)) ( * param)

  return val

 

from_tuple = from_list

  

# Cast from numpy array

def from_ndarray ( self , param):

  return param.ctypes.data_as (ctypes.POINTER (ctypes.c_double))

  

DoubleArray = DoubleArrayType ()

_ avg = _ mod.avg

_avg.argtypes = (DoubleArray, ctypes.c_int)

_ avg.restype = ctypes.c_double

 

def avg (values):

return _ avg (values, len (values))

 
# struct Point {}

class Point (ctypes.Structure):

_ fields_ = [ ( `x` , ctypes.c_double), ( ` y` , ctypes.c_double)]

 
# double distance (point *, point *)

distance = _ mod.distance

distance.argtypes = (ctypes.POINTER (Point), ctypes.POINTER (Point))

distance.restype = ctypes.c_double

Now you can easily load the module and use the resulting C functions. See the next part —