Friday, May 28, 2010

Python and C++ Integration Tutorial

Today I am going to write for the wonderful Python community out there, beauty of open-source is the huge community and help that they provide to each other through blogs, forums, mailing lists etc. So after my struggle with Python and C++ few days ago I planned to write this post to help those who may be struggling with a similar problem.

Although Python is such a great programming language in which you can do almost anything as I mentioned in my previous post but when it comes to performance and efficiency C/C++ has no competitor. So there are times especially for large-scale systems where performance cannot be sacrificed and you have to resort to C/C++ but oh no!!! Most of your source code is already in Python.........so what now?? Well not to worry. Another great thing about Python is the concept of extending it using C/C++ and that's exactly what I did. But it's easier said than done.

Calling C from Python is relatively easy but calling C++ is the real headache so I am sharing how to do it for any programmer that needs it, I had a tough time due to lack of proper tutorials on the subject and this also motivated me to write one :)

The sample class that we use here is Employee and we will use its data members and methods in Python. You can download the complete code here.

In the Employee.cpp file there is a piece of code that does the actual work, Python can call C functions with Python C API and hence its necessary to provide C extensions by keyword extern, here is the code that does it:

extern "C" {
Employee* Employee_new(){ return new Employee(); }
void Employee_promote(Employee* emp){ emp->promote(); }
void Employee_demote(Employee* emp){ emp->demote(); }
void Employee_hire(Employee* emp){ emp->hire(); }
void Employee_fire(Employee* emp){ emp->fire(); }
void Employee_display(Employee* emp){ emp->display(); }
void Employee_setFirstName(Employee* emp,char* inFirstName){ emp->setFirstName(inFirstName); }
void Employee_setLastName(Employee* emp,char* inLastName){ emp->setLastName(inLastName); }
void Employee_setEmployeeNumber(Employee* emp,int inEmployeeNumber){ emp->setEmployeeNumber(inEmployeeNumber); }
void Employee_setSalary(Employee* emp,int inNewSalary){ emp->setSalary(inNewSalary); }
}


In the code the return type of all methods is void, the constructor must have the form ClassName*...........the tough part is when you have methods that take arguments and I had quite a tough time figuring that out due to lack of tutorials on the subject. The way to do it is like this, within the extern block write the method signature as before but after the object you should have the parameter types in the signature as shown here: void Employee_setFirstName(Employee* emp,char* inFirstName){ emp->setFirstName(inFirstName); }

Now the library generation part, here's how to do it in g++

g++ -c -fPIC Employee.cpp -o Employee.o
g++ -shared -Wl,-soname,libEmployee.so -o libEmployee.so Employee.o

This will generate the dll libEmployee.so (you can give it any name of your choice) and then it can be easily called in Python. Here is an example of Python code calling a C++ class, marvelous:

from ctypes import cdll
lib = cdll.LoadLibrary('./libEmployee.so')

class Employee(object):
def __init__(self):
self.obj = lib.Employee_new()

def EmployeeTest(self):
lib.Employee_setFirstName(self.obj,"Marni")
lib.Employee_setLastName(self.obj,"Kleper")
lib.Employee_setEmployeeNumber(self.obj,71)
lib.Employee_setSalary(self.obj,50000)
lib.Employee_promote(self.obj)
lib.Employee_promote(self.obj)
lib.Employee_hire(self.obj)
lib.Employee_display(self.obj)

emp=Employee()
emp.EmployeeTest()


So ctypes does the trick and makes it quite simple........there are also other alternatives such as Boost and Swig which I have not yet explored but will do in near future as I have to work with Python and C++ for my research work for MS thesis. So stay tuned for more.

2 comments:

  1. Pretty Good Example!
    Only one hint: In the file pythonCPlusPlusTest.py (downloaded code) there are tabs instead of spaces at line 10 and below. This leads to an error of the interpreter (python 3.2).

    ReplyDelete
    Replies
    1. Thanks for pointing that out Axel. Will try to upload fixed code soon.

      Glad that you found the example helpful.

      Delete