Related Articles
Using C codes in Python | Set 1
• Last Updated : 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 ` ` `  `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 argument
avg() – performing a data reduction across a C array
Point 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.py ` `import` `ctypes ` `import` `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.gcd ` `gcd.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 *' argument ` `class` `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.distance ` `distance.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.

Attention geek! Strengthen your foundations with the Python Programming Foundation Course and learn the basics.

To begin with, your interview preparations Enhance your Data Structures concepts with the Python DS Course.

My Personal Notes arrow_drop_up
Recommended Articles
Page :