As per Wikipedia definition, "Python is an interpreted, high-level, general-purpose programming language".
Being a pythonista, we all know python is a cool language to learn and code. Thanks to its easy syntax and extensive modules.
Python is called Interpreted language, as it is not directly compiled to assembly language. Rather it first gets compiled to .pyc files which is a bytecode version of the python code and further gets compiled to assembly language, then to machine binary code to produce the output.
Making developer's life easier with its syntax and easier usage. As we don't have to declare types for the variables, as we do it in C programming language:
float decimalNumber;
int number;
decimalNumber = 3.14;
number = 10001;
where as the same code written in python:
decimal_number = 3.14
number = 10001
Python keeps track of all the variable types while it interprets the variable type for you. Hence, python is called as duck-typing. “If it walks like a duck and it quacks like a duck, then it must be a duck.” . where the right-side object type is assigned to the left-side reference.
Whereas in C programming, we declare the types of variable which reduces compiler burden and directly coverts into assembly language, then to machine binary code.
It is understandable that python has an to perform extra step, as compared to C programming language, which makes it clear that C runs faster than Python Code.
In scientific/numerical work, we might find that there are lot of computational programs which are more memory, processor intensive. In this, we know that python would subjectively fail here as python has an extra burden to talk to and fro with C to complete the job, which can reduce the performance.
Solution for this is to write an C extension which can further be used in python. By this, you will get the liberty to write the code in python and further also leverage the performance measures of C programming language.
I would like to give a small introduction to achieve that.
Get Started
(Note: When I am writing this code, I am on Linux platform. So may be the code might slightly defer when you are working on other Operating systems.)
Let us start with writing a C extension for MathLib Functions (Additions, Subtraction, Multiply, Division) which we can use in Python.
Step 1 :
Let us start with implementing the functions in C.
Create a C file with the name below
libmath.c
float addition(float num1, float num2){
float return_value = num1 + num2;
return return_value;
};
float subtract(float num1, float num2){
float return_value = num1 - num2;
return return_value;
};
float multiply(float num1, float num2){
float return_value = num1 * num2;
return return_value;
};
float divide(int num1, float num2){
float return_value = num1 / num2;
return return_value;
};
For testing your C code, you can add below main function in the same file.
#include <stdio.h> // Add this on the top, to use printf
// Other functions which we defined earlier
void main() {
printf("%f\n", addition(1.2, 3.4));
printf("%f\n", subtract(2.5, 1.5));
printf("%f\n", multiply(4, 2));
printf("%f\n", divide(4, 2));
};
Make sure you remove the main function after testing your code.
To run the code on Terminal:
gcc libmath.c && ./a.out
Step 2 :
Create PyObject Functions for the C functions which we have created. These are the functions where we will be typecast the arguments which are passed from python.
Add the below lines of code for addition function.
// Top Headers
// Other functions which we defined earlier
PyObject *cadd(PyObject * self, PyObject * args) {
float num1, num2, result;
if (!PyArg_ParseTuple(args, "ff", &num1, &num2)) {
return NULL;
}
result = addition(num1, num2);
return PyFloat_FromDouble(result);
}
PyObject *csub(PyObject * self, PyObject * args) {
float num1, num2, result;
if (!PyArg_ParseTuple(args, "ff", &num1, &num2)) {
return NULL;
}
result = subtract(num1, num2);
return PyFloat_FromDouble(result);
}
PyObject *cmul(PyObject * self, PyObject * args) {
float num1, num2, result;
if (!PyArg_ParseTuple(args, "ff", &num1, &num2)) {
return NULL;
}
result = multiply(num1, num2);
return PyFloat_FromDouble(result);
}
PyObject *cdiv(PyObject * self, PyObject * args) {
int num1;
float num2, result;
if (!PyArg_ParseTuple(args, "if", &num1, &num2)) {
return NULL;
}
result = divide(num1, num2);
return PyFloat_FromDouble(result);
}
Argument parsing is done by the below line in the above code
PyArg_ParseTuple(args, "ff", &num1, &num2)
Parses the parameters of a function that takes only positional parameters into local variables. Returns true on success; on failure, it returns false and raises the appropriate exception.
First arument - PyObject Arguments
Second Argument - Type formatting (Refer: Format Strings for PyArg_ParseTuple())
And other arguments are called Format units variables which are to be initialized.
Further declare the functions in the header files.
A header file is a file with extension . h which contains C function declarations and macro definitions to be shared between several source files.
Create a header file with the name below
libmath.h
#ifndef __LIBMYPY_H__
#define __LIBMYPY_H__
#include <Python.h>
PyObject * cadd(PyObject *, PyObject *);
PyObject * csub(PyObject *, PyObject *);
PyObject * cmul(PyObject *, PyObject *);
PyObject * cdiv(PyObject *, PyObject *);
#endif
PyObject as per official definition API Documentation
All object types are extensions of this type. This is a type which contains the information Python needs to treat a pointer to an object as an object. In a normal “release” build, it contains only the object’s reference count and a pointer to the corresponding type object. It corresponds to the fields defined by the expansion of the PyObject_HEAD
macro.
PyObject is a Python Object as defined using the Python/C API.
To declare the functions, add the line to the top of libmath.c file.
#include "libmath.h"
Step 3 :
Create a binding functions which connects the C functions to be imported as a module in python
Create a header file with the name below
bind.c
#include "libmath.h"
// Docstrings of the functions
char addfunc_docs[] = "Addition Function using C Function";
char subfunc_docs[] = "Subtract Function using C Function";
char mulfunc_docs[] = "Multiply Function using C Function";
char divfunc_docs[] = "Division Function using C Function";
// Mathlib Func Definitions
PyMethodDef mathlib_funcs[] = {
{ "add",
(PyCFunction)cadd,
METH_VARARGS,
addfunc_docs
},
{ "sub",
(PyCFunction)csub,
METH_VARARGS,
subfunc_docs
},
{ "mul",
(PyCFunction)cmul,
METH_VARARGS,
mulfunc_docs
},
{ "div",
(PyCFunction)cdiv,
METH_VARARGS,
divfunc_docs
},
{ NULL}
};
// Docstrings of the mathlib Module
char mathlib_docs[] = "This is a simple math module using C extension";
// Module Declaration as per
// https://docs.python.org/3/c-api/module.html#c.PyModuleDef
PyModuleDef mathlib_mod = {
PyModuleDef_HEAD_INIT,
"mathlib",
mathlib_docs,
-1,
mathlib_funcs,
NULL,
NULL,
NULL,
NULL
};
// Module Initialization
PyMODINIT_FUNC PyInit_mathlib(void) {
return PyModule_Create(&mathlib_mod);
}
Step 4 :
Finally let us wrap up the code by adding a setup file, so that your module can be installable as a package. (Refer : Building C and C++ Extension)
from setuptools import setup, Extension
setup(
name = "mathlib",
version = "1.0",
ext_modules = [Extension("mathlib", ["bind.c", "libmath.c"])]
);
Thats it, we are good to use our mathlib module in Python.
Final Step :
You have to build the Mathlib module in your enviroment. Open terminal and run the following command in the working directory.
python setup.py build_ext --inplace
This will create a file named mathlib.cpython-36m-x86_64-linux-gnu.so and build the files in build folder, ready to be installed/use as a module.
Create a python file to test Mathlib module which we have created
test.py
import mathlib
print(f'Using it in python')
print(f' Adding 1.2 and 1.3 results to {mathlib.add(1.2, 2.3)}')
print(f' Subtracting 1.5 from 2.5 results to {mathlib.sub(2.5, 1.5)}')
print(f' Multiplying 4 with 2 results to {mathlib.mul(4, 2)}')
print(f' Dividing 4 by 2 results to {mathlib.div(4, 2)}')
# Print Mathlib Documentation
# print(help(mathlib))
Conclusion:
So this way we can use functions written in C language and extend it to be used in Python as a module.
The example above is a short demostrative implementation of math module which we use in python.
>>> import math
>>> math.sqrt(4)
2.0
Hopefully, after reading through the article, you should be able to write your own C extension in Python.
Read more on Python C extensions.
Get the source code of the article on the below link
Working with C in Python - C Extension Sample Module
Powered by Froala Editor