Making C and Python Talk to Each Other

1.0 Introduction

LeetArxiv is Leetcode for implementing Arxiv and other research papers. We code lots of research papers and these tend to be in C and Python*. Due to popular demand, we wrote this comprehensive guide to interfacing between these languages.
Stop reading papers. Start coding them. Subscribe for weekly paper implementations, one semicolon at a time.
*Foundational research papers (✨from before the 2000's✨) tend to be in C while modern AI research papers are in Python.
This practical coding guide demonstrates how to : Call Python from C and embed Python scripts in your C codebase.
We’ll start from the complete basics.
2.0 Calling Python inside C
Say you have a Python file, let’s call it PythonFunctions.py
. Now you want to use these functions inside a C file, let’s call this Cmain.c
.
We assume you’re working on Linux or a Mac*. We also assume you have Python 3 and GCC available on your system.
*Using C on Windows is pretty cumbersome lol
2.1 Locating Python.h
You need to include Python.h
inside your C to file to proceed.
To locate Python.h, open a terminal and type :
python3-config --includes
In my terminal, I get this path to Python.h :
2.2 Including Python Header File in C
Now, we need to call the Python header file after we located Python.h.
I’m using Python 3.8, so I modify Cmain.c
to this :
2.3 Compiling Our C file
Sanity check : we need to compile our Cmain.c
to ensure everything is working.
To achieve this, we add the path to our Python installation (we located Python.h in Section 2.1) then link Python 3.8 in GCC.
The final GCC command resembles this :
gcc Cmain.c -I/usr/include/python3.8 -lpython3.8 -o Cmain.o
If everything is working then this small program should run :
2.4 Working with PyObjects
From here onwards, we are following the official Python documentation. PyObjects are structures used in the definition of object types for Python(Common Object Structures 2025). This simply means : everything is a PyObject.
2.4.1 Setting Environment Variables, Initializing and Finalizing Python
First, we use Python’s
os.setenv
function to create a path to ourPythonFunctions.py
file.We use ./ since it’s in the same directory as our C
main.c .
After setting the path, we need to initialize Python using
Py_Initialize.
Py_Initialize
initializes the Python Interpreter.
Then we end the Python session using
Py_Finalize.
Py_Finalize
undoes all the initializations and destroys all sub-interpreters.
The code below runs :
char *pythonFileLocation = "./";
//Set environment
setenv("PYTHONPATH", pythonFileLocation, 1);
//Initialize Python
Py_Initialize();
//End Python Session
Py_Finalize();
*The curious may see lots of Valgrind errors. Don’t worry. We’ll handle these later.
2.4.2 Loading a Module and Freeing Module Memory
Now, we load the file containing our actual Python code, PythonFunctions.py
. We free this memory using the Py_XDECREF
function.
*In the docs, there is a Py_DECREF
but Py_XDECREF
is better to use the latter because it can handle null values.
char *pythonFileName = "PythonFunctions";
PyObject *loadModule = PyImport_ImportModule(pythonFileName);
if(loadModule == NULL)
{
/*Need to set path to overcome this error*/
printf("Error importing module\n");
PyErr_Print();
exit(1);
}
//Cleanup Load Module
Py_XDECREF(loadModule);
Your entire main function should resemble this :
2.5 Calling Python Functions
First, we’ll write three Python functions inside PythonFunctions.py .
2.5.1 Calling Functions Without Arguments
Remember, everything is a PyObject. Here are the steps :
Load the Function name into a PyObject using
PyObject_GetAttrString.
Call the Function by its name using
PyObject_CallObject.
Free the two newly-create PyObjects using separate
Py_XDECREF.
PyObject *currentDirectoryFunction = PyObject_GetAttrString(loadModule, (char *)"PrintCurrentDirectory");
if(currentDirectoryFunction == NULL)
{
printf("Error loading currentDirectoryFunction\n");
PyErr_Print();
exit(1);
}
//Argument is Null because function takes zero arguments
PyObject *directoryFunctionCall = PyObject_CallObject(currentDirectoryFunction, NULL);
if(directoryFunctionCall == NULL)
{
printf("Error calling directoryFunctionCall\n");
PyErr_Print();
exit(1);
}
//Cleanup Call to Directory Function
Py_XDECREF(directoryFunctionCall);
//Cleanup Current Directory Function
Py_XDECREF(currentDirectoryFunction);
2.5.2 Calling Functions With Arguments
Let’s work with the PrintList function. The function takes 1 argument, a python List type. Here are the steps to call it :
Create a new list object using
PyList_New
.Create an integer object using
PyLong_FromLong.
Load the integer inside the list using
PyList_SetItem.
Create a tuple to hold function arguments using
PyTuple_Pack.
Cleanup the list and function arguments.*
*I might be mistaken but a really interesting observation is : Calling
Py_XDECREF
onpythonList
is sufficient to free the integer within the list.
int numberOfArguments = 1;
int listLength = 1;
//Create a new list
PyObject *pythonList = PyList_New(listLength);
if(pythonList == NULL)
{
printf("Error creating Python List\n");
PyErr_Print();
exit(1);
}
//Create a new integer
PyObject *pythonInteger = PyLong_FromLong(55);
if(pythonInteger == NULL)
{
printf("Error creating Python Int\n");
PyErr_Print();
exit(1);
}
//Set integer at list index 0
PyList_SetItem(pythonList, 0, pythonInteger);
PyObject *functionArguments = PyTuple_Pack(numberOfArguments, pythonList);
//Cleanup functionArguments
Py_XDECREF(functionArguments);
//Cleanup pythonList
Py_XDECREF(pythonList);
All the code you need to call PrintList should resemble this :
Try calling PrintSum on your own :)
If you’re lost then feel free to compare your code with mine.
This is the link to the C File and Python File.
3.0 Conclusion
In this article, you learnt how to call Python code within a C codebase.
Subscribe if you made it this far.
References
Python Software Foundation. (2025). Common Object Structures. Link
Python Software Foundation. (2025). Py_Initialize. Link
Python Software Foundation. (2025). Py_Finalize. Link
Python Software Foundation. (2025). Py_XDECREF. Link
What's Your Reaction?






