https://leetarxiv.substack.com/p/making-c-and-python-talk-to-each LeetArxiv LeetArxiv SubscribeSign in Share this post [https] LeetArxiv LeetArxiv Making C and Python Talk to Each Other Copy link Facebook Email Notes More Making C and Python Talk to Each Other How to Use Python in C Murage Kibicho's avatar Murage Kibicho May 27, 2025 4 Share this post [https] LeetArxiv LeetArxiv Making C and Python Talk to Each Other Copy link Facebook Email Notes More 2 1 Share 1.0 Introduction In Part 2, we learn how to use the native Tensorflow C API to train/ build models. Sign up [ ] Subscribe [https] Summary of calling Python from C and C from Python 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. [ ] Subscribe *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 C main.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 : [https] Python Installation Path 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 : [https] Adding Python.h to a C file 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 : [https] Sanity Check to Ensure Python Call Works 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 20251). This simply means : everything is a PyObject. 2.4.1 Setting Environment Variables, Initializing and Finalizing Python 1. First, we use Python's os.setenv function to create a path to our PythonFunctions.py file. + We use ./ since it's in the same directory as our Cmain.c . 2. After setting the path, we need to initialize Python using Py_Initialize. + Py_Initialize initializes the Python Interpreter2. 3. Then we end the Python session using Py_Finalize. + Py_Finalize undoes all the initializations and destroys all sub-interpreters3. 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_XDECREF4 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 : [https] Main file 2.5 Calling Python Functions First, we'll write three Python functions inside PythonFunctions.py . [https] Modified Python File 2.5.1 Calling Functions Without Arguments Remember, everything is a PyObject. Here are the steps : 1. Load the Function name into a PyObject using PyObject_GetAttrString. 2. Call the Function by its name using PyObject_CallObject. 3. 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 : 1. Create a new list object using PyList_New. 2. Create an integer object using PyLong_FromLong. 3. Load the integer inside the list using PyList_SetItem. 4. Create a tuple to hold function arguments using PyTuple_Pack. 5. Cleanup the list and function arguments.* *I might be mistaken but a really interesting observation is : Calling Py_XDECREF on pythonList 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 : [https] Calling a function with arguments 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. [ ] Subscribe References 1 Python Software Foundation. (2025). Common Object Structures. Link 2 Python Software Foundation. (2025). Py_Initialize. Link 3 Python Software Foundation. (2025). Py_Finalize. Link 4 Python Software Foundation. (2025). Py_XDECREF. Link 4 Share this post [https] LeetArxiv LeetArxiv Making C and Python Talk to Each Other Copy link Facebook Email Notes More 2 1 Share Discussion about this post CommentsRestacks User's avatar [ ] [ ] [ ] [ ] Jasmine Belmont's avatar Jasmine Belmont 13h Liked by Murage Kibicho Great walkthrough! Embedding Python into C isn't as commonly discussed as extending Python with C, so this was a refreshing perspective. The step-by-step guide on setting up the environment and handling PyObject references was particularly helpful. Looking forward to more content like this! Expand full comment Reply Share 1 reply by Murage Kibicho 1 more comment... TopLatestDiscussions No posts Ready for more? [ ] Subscribe (c) 2025 Murage Kibicho Privacy [?] Terms [?] Collection notice Start writingGet the app Substack is the home for great culture Share Copy link Facebook Email Notes More This site requires JavaScript to run correctly. Please turn on JavaScript or unblock scripts