When developing an application in programming language A you may discover that certain parts of the program are easier to code using a different language B. At this point you have one of three choices:
- Write the application entirely in language A.
- Write the application entirely in language B.
- Write most of the application using language A and call language B from A when appropriate.
The downsides of the first two approaches are that you sacrifice the benefits of writing parts of the application in one language for the sake of using a uniform language. By using the third approach you overcome these downsides at the cost of the context switching required to start executing code in a different language. However, depending on the frequency with which the program will execute code written in language B, this trade-off may be acceptable.
In the Active Authentication project we are writing C++ code that leverages the Detours library to collect system call traces. However, there are several implementations of algorithms used to process these system call traces that are available in Python. We could translate these algorithms to C++, but because this is a research project we decided to refrain from doing so until we had evidence that calling the Python code from C++ incurs an unacceptable time overhead. In this post I will, through the use of a simple example, describe how to call a Python function from C++ and retrieve its return value. I will assume that you already have Microsoft Visual Studio and Python installed on your computer. The following example was tested with Visual Studio 2010 Professional and Python 2.7.3.
Creating the Visual Studio Project
Open Visual Studio and create a new C++ “Win32 Console Application” project. Before you can call Python code you need to tell Visual Studio how to find Python. Before doing this change the build mode from “Debug” to “Release”. If you attempt to build a Visual Studio project that calls Python code in Debug mode the build will fail because, in debugging mode, Visual Studio will look for a library file that does not exist. The reason why this file did not exist on my machine is because the Windows Python installer did not install a version of Python compiled in Debug mode. It is possible to get a version of Python built in Debug mode, but you will have to download the Python source code and build it manually. For the purposes of this blog post we will ignore this and just change to Release mode.
Next you need to add the locations of the Python header and library files to the project properties. My Python installation directory was “C:\Python27”, so I added “C:\Python27\include” to the list of include directories and “C:\Python27\libs” to the list of library directories. After making these changes to the properties you should be able to add the line “#include <Python.h>” to the C++ source file and build the project without error.
You can now replace the contents of your C++ source file with the following source code example:
#include “stdafx.h”
#include <iostream>
#include <Python.h>
int _tmain(int argc, _TCHAR* argv[])
{
printf(“Calling Python to find the sum of 2 and 2.\n”);
// Initialize the Python interpreter.
Py_Initialize();
// Create some Python objects that will later be assigned values.
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
// Convert the file name to a Python string.
pName = PyString_FromString(“Sample”);
// Import the file as a Python module.
pModule = PyImport_Import(pName);
// Create a dictionary for the contents of the module.
pDict = PyModule_GetDict(pModule);
// Get the add method from the dictionary.
pFunc = PyDict_GetItemString(pDict, “add”);
// Create a Python tuple to hold the arguments to the method.
pArgs = PyTuple_New(2);
// Convert 2 to a Python integer.
pValue = PyInt_FromLong(2);
// Set the Python int as the first and second arguments to the method.
PyTuple_SetItem(pArgs, 0, pValue);
PyTuple_SetItem(pArgs, 1, pValue);
// Call the function with the arguments.
PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
// Print a message if calling the method failed.
if(pResult == NULL)
printf(“Calling the add method failed.\n”);
// Convert the result to a long from a Python object.
long result = PyInt_AsLong(pResult);
// Destroy the Python interpreter.
Py_Finalize();
// Print the result.
printf(“The result is %d.\n”, result); std::cin.ignore(); return 0; }
Since the code comments describe the purpose of almost every statement I will simply describe what the code does at a high level. This program calls a Python function that returns the sum of two numbers. First the program creates a Python interpreter so that it can execute Python code. The program then retrieves the method from the Python source file and prepares the arguments that will be sent to the method. The C++ code then calls the function, retrieves the result, and destroys the Python interpreter. Finally, the program prints the result of adding 2 and 2. Now that the C++ code is ready you need to write the Python code that will be called.
Creating the Python File
Next you should add the Python function “add” that will be called from C++ to a file named “Sample.py”. The code for this function is:
# Returns the sum of two numbers.
def add(a, b):
return a+b
Add this file to the Release directory of the Visual Studio solution. In general it should be in the same directory as the executable that is calling the Python code.
After creating the Python file you should be able to run the Visual Studio project and see the following output:
Calling Python to find the sum of 2 and 2. The result is 4.
Future Work
In the Active Authentication project we created Python objects that we accessed and modified throughout the execution of a C++ program. In a future post I may describe how to manage Python objects from C++ and serialize them so that they can be accessed during subsequent program executions. Another possible topic for a future post is a performance comparison of two versions of some simple (yet realistic) C++ program – one that executes a subroutine written in C++ and another that calls Python code to perform the same task.
22 thoughts to “Calling Python Code from C++”
If the above code doesn’t work, try adding the following lines just below Py_Initialize();
PyRun_SimpleString(“import sys”);
PyRun_SimpleString(“sys.path.append(\”.\”)”);
Hi, I have added the above PyRun_SimpleString() two lines. Still my pFunc is 0 after executing
PyDict_GetItemString(pDict, “Solver”); Solver is the function name defined in my python codes.
Could anyone give a hint what is being wrong? Thanks.
Hi Jessica,
What is the name of the .py file that contains the “Solver” function? Does it match the parameter passed to this method?:
pName = PyString_FromString(“YourFileName”);
Jonathan
Hi, first of all thanks for this article, it has been very useful so far. However, I haven’t be able to make it work yet. I have the following code:
Py_Initialize();// Initialize the Python interpreter.
std::cout << "Python interpreter intialized" << std::endl;
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;// Create some Python objects that will later be assigned values.
std::cout << "Python objects created" << std::endl;
pName = PyUnicode_FromString("test");// Convert the file name to a Python string.
if (pName == NULL) {
std::cout << "ERROR: name pointer is null" << std::endl;
}
else {
std::cout << "Name of the python module assigned" << std::endl;
}
pModule = PyImport_Import(pName);// Import the file as a Python module.
if (pModule == NULL) {
std::cout << "ERROR: module pointer is null" << std::endl;
}
else {
std::cout << "Python module imported" << std::endl;
}
pDict = PyModule_GetDict(pModule);// Create a dictionary for the contents of the module.
if (pDict == NULL) {
std::cout << "ERROR: dictionary pointer is null" << std::endl;
}
else {
std::cout << "Python dictionary of the module functions created" << std::endl;
}
//pFunc = PyDict_GetItemString(pDict, "add");// Get the add method from the dictionary.
pFunc = PyUnicode_FromString("add");
if (pFunc == NULL) {
std::cout << "ERROR: function pointer is null" << std::endl;
}
else {
std::cout << "Python function found" << std::endl;
}
pArgs = PyTuple_New(2);// Create a Python tuple to hold the arguments to the method.
if (pArgs == NULL) {
std::cout << "ERROR: Arguments pointer is null" << std::endl;
}
else {
std::cout << "Python arguments tuple created" << std::endl;
}
pValue = PyLong_FromLong(2);// Convert 2 to a Python integer.
if (pValue == NULL) {
std::cout << "ERROR: Value pointer is null" << std::endl;
}
else {
std::cout << "Python argument value assgined" << std::endl;
}
PyTuple_SetItem(pArgs, 0, pValue);// Set the Python int as the first and second arguments to the method.
PyTuple_SetItem(pArgs, 1, pValue);
std::cout << "Python arguments assgined to tuple" << std::endl;
PyObject* pResult = PyObject_CallObject(pFunc, pArgs);// Call the function with the arguments.
if (pResult == NULL) {
std::cout << "ERROR: Result pointer is null" << std::endl;// Print a message if calling the method failed.
}
else {
long result = PyLong_AsLong(pResult);// Convert the result to a long from a Python object.
std::cout << "The result is " << result;// Print the result.
}
Py_Finalize();// Destroy the Python interpreter.
But i get:
Python interpreter intialized
Python objects created
Name of the python module assigned
Python module imported
Python dictionary of the module functions created
Python function found
Python arguments tuple created
Python argument value assgined
Python arguments assgined to tuple
ERROR: Result pointer is null
The python code is just test.py:
def add(a, b):
return a+b
I am using visul studio if it is of any relevance.
Thanks in advance for your time!
Hi Miguel,
The documentation for the PyObject_CallObject method indicates that the method both returns NULL and raises an exception when it fails. Can you provide the details of the exception that is raised as well?
Jonathan
Python interpreter intialized
Python objects created
Name of the python module assigned
ERROR: module pointer is null
Hi Sushant,
What is the name of the .py file with the method that you want to call? Does the name of the file match the argument passed to the following method?
pName = PyUnicode_FromString(“test”);
Jonathan
I receive Segmentation fault (core dumped) when i run the code.
Hi Mohamed,
Are there any differences between your code and the code in the post? Can you provide more details about your environment, such as the versions of Visual Studio and Python that you are using?
Jonathan
hi I can not add my Python file to the Release directory of the Visual Studio solution.could you tell me how I should proceed in Visual Studio? then whithout the addition I receive an execution of the type: Exception raised to 0x00007FFF92660FD4 (python37 .dll) in python_to_cpp.exe: 0xC0000005: location of reading the access violation 0x00000000000000000008. occurred
below my c ++ and python code
######### c code ++ ########################################################################
#include
#include
int main(int argc, const wchar_t* argv[])
{
// Initialize the Python interpreter.
Py_Initialize();
// Create some Python objects that will later be assigned values.
PyObject* pName, * pModule, * pDict, * pFunc, * pArgs, * pValue;
// Convert the file name to a Python string.
pName = PyUnicode_FromString(“C:/Users/siand/Downloads/test”);
//pName = PyString_FromString(“C:/test.py”);
// Import the file as a Python module.
pModule = PyImport_Import(pName);
// Create a dictionary for the contents of the module.
pDict = PyModule_GetDict(pModule);
// Get the add method from the dictionary.
pFunc = PyDict_GetItemString(pDict, “add”);
// Create a Python tuple to hold the arguments to the method.
pArgs = PyTuple_New(2);
// Convert 2 to a Python integer.
pValue = PyLong_FromLong(2);
//pValue = PyInt_FromLong(2);
// Set the Python int as the first and second arguments to the method.
PyTuple_SetItem(pArgs, 0, pValue);
PyTuple_SetItem(pArgs, 1, pValue);
// Call the function with the arguments.
PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
// Print a message if calling the method failed.
if (pResult == NULL)
printf(“Calling the add method failed.\n”);
// Convert the result to a long from a Python object.
long result = PyLong_AsLong(pResult);
//long result = PyInt_AsLong(pResult);
// Destroy the Python interpreter.
Py_Finalize();
// Print the result.
printf(“The result is % d.\n”, result);
std::cin.ignore();
return 0;
}
### python code ki is stored in C: /Users/sam/Downloads/test.py on my computer ###
def add (a, b):
return a + b
if __name __ == “__ main__”:
print ( hello )
a = input (“a:”)
b = entry (“b:”)
print (add (int (a), int (b))
Hi Patrick,
Why are you not able to add the Python file to the Release directory? Does the directory not exist? Or is there some problem with adding the file to it?
Jonathan
Thanks for your quick response Jonathan.
I don’t know where to put the Python code in the visual studio.
ist it unter:
>project_name
>property
> C/C++
> General ->Additionale include directry
the path to my Python code is C:\Users\sam\Downloads\test.py
thanks
If you navigate to the project using Windows Explorer you should be able to find a Release directory. I think that there might be multiple Release directories, so you’ll have to do some experimentation to figure out which one works.
I still get this execption: Exception thrown at 0x00007FFF930B0FD4 (python37.dll) in python_to_cpp.exe: 0xC0000005: Access violation reading location 0x0000000000000008.
Did you update the following line after moving the Python file to the Release directory?
pName = PyUnicode_FromString(“C:/Users/siand/Downloads/test”);
If not, and your Python file is named test.py, you should change that line to:
pName = PyUnicode_FromString(“test”);
yes I did it.but i got it as output:
######### Output ###############
Name of the python module assigned
Python module imported
Python dictionary of the module functions created
Python function found
Python arguments tuple created
ERROR: Value pointer is null
Python argument value assgined
Calling the add method failed. 🙁
SystemError: G:\ade\build\sb_0-36732646-1573733864.51\Python-3.7.4-export-15549617\Python-3.7.4\Objects\longobject.c:415: bad argument to internal function
The result is -1.
#### my new code c++ is:
#include
#include
//#include
//#include
int main(int argc, const wchar_t* argv[])
{
//char filename[] = “D:/Master-Computer-engenniering/Semester 2/Lego_Projekt_entwicklung_Thomas/train_lego_with_Mobilnet/lego_Test.py”;
// char filename[] = “C:/test.py”;
//FILE* fp;
//Py_SetProgramName(argv[0]);
// Initialize the Python interpreter.
Py_Initialize();
// Create some Python objects that will later be assigned values.
PyObject* pName, * pModule, * pDict, * pFunc, * pArgs, * pValue;
// Convert the file name to a Python string.
pName = PyUnicode_FromString(“test”);
//pName = PyString_FromString(“C:/test.py”);
if (pName == NULL)
{
std::cout << "ERROR: name pointer is null" << std::endl;
}
else {
std::cout << "Name of the python module assigned" << std::endl;
}
// Import the file as a Python module.
pModule = PyImport_Import(pName);
if (pModule == NULL) {
std::cout << "ERROR: module pointer is null" << std::endl;
}
else {
std::cout << "Python module imported" << std::endl;
// Create a dictionary for the contents of the module.
}
pDict = PyModule_GetDict(pModule);
if (pDict == NULL) {
std::cout << "ERROR: dictionary pointer is null" << std::endl;
}
else {
std::cout << "Python dictionary of the module functions created" << std::endl;
}
// Get the add method from the dictionary.
//pFunc = PyDict_GetItemString(pDict, "add");
pFunc = PyUnicode_FromString("add");
if (pFunc == NULL) {
std::cout << "ERROR: function pointer is null" << std::endl;
}
else {
std::cout << "Python function found" << std::endl;
}
// Create a Python tuple to hold the arguments to the method.
pArgs = PyTuple_New(2);
if (pArgs == NULL) {
std::cout << "ERROR: Arguments pointer is null" << std::endl;
}
else {
std::cout << "Python arguments tuple created" << std::endl;
}
// Convert 2 to a Python integer.
pValue = PyLong_FromLong(2);
if (pValue == NULL) {
std::cout << "ERREUR: le pointeur de valeur est nul" << std::endl;
}
else {
std::cout << "ERROR: Value pointer is null" << std::endl;
}
//pValue = PyInt_FromLong(2);
// Set the Python int as the first and second arguments to the method.
PyTuple_SetItem(pArgs, 0, pValue);
PyTuple_SetItem(pArgs, 1, pValue);
std::cout << "Python argument value assgined" << std::endl;
// Call the function with the arguments.
PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
// Print a message if calling the method failed.
if (pResult == NULL)
printf("Calling the add method failed.\n");
// Convert the result to a long from a Python object.
long result = PyLong_AsLong(pResult);
//long result = PyInt_AsLong(pResult);
// Destroy the Python interpreter.
Py_Finalize();
// Print the result.
printf("The result is % d.\n", result);
std::cin.ignore();
return 0;
}
### Python code #########
def add(a,b):
return a+b
if __name__=="__main__":
print("hello ")
a=2
b=5
b=add(a,b)
print(b)
I see that you’re using PyLong_AsLong instead of PyInt_AsLong — maybe try using “2L” instead of “2” to force the int to be a long? I don’t have this project set up anymore, so I unfortunately can’t try things out myself.
Pingback: Cannot import Python.h – Windows Questions
Pingback: I can’t include python.h in omnet – Windows Questions
Pingback: I can’t include python.h in omnet – Ask python questions
Hey thx for the great work. I run in a Problem with my code. Hope you can help
Code i use
Py_Initialize();// Initialize the Python interpreter.
std::cout << "Python interpreter intialized" << std::endl;
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;// Create some Python objects that will later be assigned values.
std::cout << "Python objects created" << std::endl;
pName = PyUnicode_FromString("test");// Convert the file name to a Python string.
if (pName == NULL) {
std::cout << "ERROR: name pointer is null" << std::endl;
}
else {
std::cout << "Name of the python module assigned" << std::endl;
}
pModule = PyImport_Import(pName);// Import the file as a Python module.
if (pModule == NULL) {
std::cout << "ERROR: module pointer is null" << std::endl;
}
else {
std::cout << "Python module imported" << std::endl;
}
pDict = PyModule_GetDict(pModule);// Create a dictionary for the contents of the module.
if (pDict == NULL) {
std::cout << "ERROR: dictionary pointer is null" << std::endl;
}
else {
std::cout << "Python dictionary of the module functions created" << std::endl;
}
//pFunc = PyDict_GetItemString(pDict, "add");// Get the add method from the dictionary.
pFunc = PyUnicode_FromString("add");
if (pFunc == NULL) {
std::cout << "ERROR: function pointer is null" << std::endl;
}
else {
std::cout << "Python function found" << std::endl;
}
pArgs = PyTuple_New(2);// Create a Python tuple to hold the arguments to the method.
if (pArgs == NULL) {
std::cout << "ERROR: Arguments pointer is null" << std::endl;
}
else {
std::cout << "Python arguments tuple created" << std::endl;
}
pValue = PyLong_FromLong(2);// Convert 2 to a Python integer.
if (pValue == NULL) {
std::cout << "ERROR: Value pointer is null" << std::endl;
}
else {
std::cout << "Python argument value assgined" << std::endl;
}
PyTuple_SetItem(pArgs, 0, pValue);// Set the Python int as the first and second arguments to the method.
PyTuple_SetItem(pArgs, 1, pValue);
std::cout << "Python arguments assgined to tuple" << std::endl;
PyObject* pResult = PyObject_CallObject(pFunc, pArgs);// Call the function with the arguments.
if (pResult == NULL) {
std::cout << "ERROR: Result pointer is null" << std::endl;// Print a message if calling the method failed.
}
else {
long result = PyLong_AsLong(pResult);// Convert the result to a long from a Python object.
std::cout << "The result is " << result;// Print the result.
}
Py_Finalize();// Destroy the Python interpreter.
But i get:
Python interpreter intialized
Python objects created
Name of the python module assigned
Python module imported
Python dictionary of the module functions created
Python function found
Python arguments tuple created
Python argument value assgined
Python arguments assgined to tuple
ERROR: Result pointer is null
TypeError : `str` object is not callable
The python code is just test.py:
def add(a, b):
return a+b
I use a viruelle Linux machine and QT.
Hi Nicola,
I think that this line might be the problem:
pFunc = PyUnicode_FromString(“add”);
Instead of returning a function reference, this line will return a Unicode object. I see that you have the line that was in the original post commented out:
//pFunc = PyDict_GetItemString(pDict, “add”);// Get the add method from the dictionary.
What happens if you use the commented-out line instead?
Jonathan