DEV Community

How to Use C Functions in Python

Erik on August 04, 2019

Did you know you can write functions in C and then call them directly from Python? Isn't that cool? Let's skip all the background and the "why woul...
Collapse
 
jankislinger profile image
Jan Kislinger

Great example! Do you know if there is any tool to help you with using it in a package? So that if you install the package (using setup.py) it automatically compiles the C code and links paths to shared objects. Maybe even writes the wrapper function in Python. Something like Rcpp for R.

Collapse
 
erikwhiting88 profile image
Erik

Hi Jan! Off the top of my head, I don't know of anything, but have a look at Fernando B (@kodaman2 ) comment a couple comments down. He mentions SIP that can turn C or C++ bindings. If you can't find the comment, this is the link he provided: pypi.org/project/SIP/

Collapse
 
thefern profile image
Fernando B 🚀

I dunno if sip is a fully automated solution, have a look at this project I believe you have to manually write the sip file (wrapper), but I could be wrong. I've never actually successfully compiled with sip.

github.com/dimv36/QCustomPlot-PyQt5

Collapse
 
markboer profile image
Mark Boer

There is quite a few ways to interface Python with C/C++. I hadn't heard of SIP before, but I think SWIG and Shiboken should be fairly similar in creating bindings automagically.

Personally I'm a big fan of Cython and pybind11. Cython was created to be able to transpile a python-like syntax to C to then compile it, but it can also be used to wrap C libraries or to interface with C code.

Pybind11 is similar to BoostPython as in that is was meant to expose C functionality to Python similar to what is being done in this article, but it also helps with converting types such as lists and tuples and makes it easier to manipulate the GIL.

If you are interested in this topic I have a talk on embedding Python into C++. Pretty much the exact opposite of this :P

Collapse
 
rpalo profile image
Ryan Palo

This is a really neat article, I didn't know it was this easy! Because I'm not familiar with the ctypes module, and from ctypes import * makes it a little tough to see which functionality is coming from ctypes, is it just the CDLL class that you're using from there?

Collapse
 
erikwhiting88 profile image
Erik

Yes! and thank you for pointing out the lack of clarity. the CDLL is the only thing in the Python script coming from the ctypes module

Collapse
 
stefano1511 profile image
Stefano1511

Hi!, great example. It was very useful. I have one question... I don't know if is only me but when my number is 13 (or bigger) the code from C doesn't work. Anyone has the same problem?

Collapse
 
erikwhiting88 profile image
Erik

it's probably because 13! is 6.2 billion and it's possible your compiler only sets aside enough memory for 4.2 billion for long. try long long and see if you get the same problem

Collapse
 
stefano1511 profile image
Stefano1511

Hi Erik, thanks for the reply. I did your recommendation but it doesn't work. I was thinking that the problem is with gcc but I am not sure. Do you have any other idea?

Thread Thread
 
erikwhiting88 profile image
Erik

I tried it out too. It's definitely weird. It's "working" for me but it's not giving me the right answer. I never tested that high. I'm at work now and can't really dig into it but if I get some time I'll let you know.

Thread Thread
 
stefano1511 profile image
Stefano1511

Sure, thanks again!

Thread Thread
 
benh42 profile image
Ben Hartley

Not sure if this thread will be active again, but I found that on the c side of the program (using long long) it is accurate up to 20! . I found this by adding a printf statement in cfactorial.c . So it seems that at some point in the process of python and c communicating, the true value is lost.

Thread Thread
 
erikwhiting88 profile image
Erik

interesting. perhaps ints in C are represented differently in memory than in Python. maybe the best way is to parse the int into a char array and send it to Python as a string?

Thread Thread
 
benh42 profile image
Ben Hartley

That does sound promising because I imagine it could scale almost indefinitely if its not bound by the long or long long limits

Collapse
 
mujeebishaque profile image
Mujeeb Ishaque

noob question: Is it going to have the same performance as the performance of c programming language code.

Collapse
 
erikwhiting88 profile image
Erik

the work that the C function is doing will be equally as fast. running The C function though the Python script will add a little latency because the Python script is doing a couple things before calling the function, but the difference in time should be negligible

Collapse
 
mujeebishaque profile image
Mujeeb Ishaque

One more question, is it going to be the same for c++ code?

Collapse
 
erikwhiting88 profile image
Erik

I am not sure if this will work exactly the same with C++. the first difference that comes to mind is using g++ instead of cc

the ctypes library seems to be optimized for C specifically but I bet you can use c++ as well. I'm not in a place where I can test this out right now, but play around with it and let me know what you learn

Thread Thread
 
mujeebishaque profile image
Mujeeb Ishaque

Thank you so much. I will try it out and would share the results. Thanks once again, Mr. Erik.

Collapse
 
akshaynp profile image
Akshay Panajwar

Hi Erik,

Thanks for this nice explanation.

Can you also please share the example wherein the C program function will return char* and how to reinterpret this data in python code.

Thanks in advance.

Collapse
 
thefern profile image
Fernando B 🚀

Great read, have you used sip? pypi.org/project/SIP/ it can turn full c or c++ libs to python bindings. I've never had the need to use it, but looks promising.

Collapse
 
erikwhiting88 profile image
Erik

interesting, I've not heard of this before. will check it out!

Collapse
 
iceorfiresite profile image
Ice or Fire

This is really helpful for times when you can't find python libraries to do what you need or if you need C because it runs faster. Thanks for sharing!