Using C codes in Python | Set 1 - GeeksforGeeks

18 Mar, 2019
Prerequisite: How to Call a C function in Python
Let’s discuss the problem of accessing C code from Python. As it is very evident that many of Python’s built-in libraries are written in C. So, to access C is a very important part of making Python talk to existing libraries. There is an extensive C programming API that Python provides but there are many different to deal with C.
Code #1 : [work.c] C-Code that we are dealing.
#include <math.h>  int gcd(int x, int y){    int g = y;    while (x > 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 < n; i++)    {        total += a[i];    }    return total / n;}  typedef struct Point{    double x, y;} Point;  double distance(Point * p1, Point * p2){    return hypot(p1->x - p2->x, p1->y - p2->y);}
Above code has different C-programming features.
gcd()divide() – returning multiple values, one through a pointer argumentavg() – performing a data reduction across a C arrayPoint and distance() – involve C structures.
Let’s assume that the code above is found in a file named work.c and it has been compiled into a library libsample that can be linked to other C code. Now, we have a number of C functions that have been compiled into a shared library. So, we call the functions entirely from Python without having to write additional C code or using a third-party extension tool. Using ctypes :Python ctypes will come to play but make sure the C code, that is 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.).
Further the libsample.so file has been placed in the same directory as the work.py. Let’s understand work.py now.
Code #2 : Python module that wraps around resulting library to access it
# work.pyimport ctypesimport os  # locating the 'libsample.so' file in the# 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 : Accessing code
# int gcd(int, int)gcd = _mod.gcdgcd.argtypes = (ctypes.c_int, ctypes.c_int)gcd.restype = ctypes.c_int  # int divide(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 'double *' argumentclass DoubleArrayType:    def from_param(self, param):                  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):        if 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 a 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.distancedistance.argtypes = (ctypes.POINTER(Point), ctypes.POINTER(Point))distance.restype = ctypes.c_double
Now, one can easily load the module and use the resulting C functions. See the next part – Using C codes in Python | Set 2.
python-utility
Python
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Comments
Old Comments
Python Dictionary
Enumerate() in Python
Read a file line by line in Python
Defaultdict in Python
Different ways to create Pandas Dataframe
sum() function in Python
Iterate over a list in Python
How to Install PIP on Windows ?
Deque in Python
Python String | replace()