--Pass the value calculated in the C / C ++ source to the python function, and receive the execution result in the C / C ++ source.
--Create an appropriate value in C / C ++ --Print the value with a python function --python functions also return appropriate values --Print the value returned by the python function on the C / C ++ side as well.
(The values of variables used in the program have no meaning)
C/C++
main.cpp
#include <iostream>
#include <vector>
#include <Python.h>
bool isCallable(const char *functionName, PyObject *pythonFunc) {
    if (pythonFunc && PyCallable_Check(pythonFunc)) {
        return true;
    } else {
        std::cerr << "Failed to load the function [" << functionName << "]." << std::endl;
        return false;
    }
}
int main(int argc, char *argv[]) {
    const char *pythonFileName = "script"; // The extension (.py) must be removed.
    const char *functionName = "test_func"; // This function must be included in the script.
    Py_Initialize();
    PyObject *sys = PyImport_ImportModule("sys");
    PyObject *path = PyObject_GetAttrString(sys, "path");
    PyList_Append(path, PyString_FromString(".")); // Add the current directory to the python path list since the script file is in there.
    PyRun_SimpleString("import os, sys\n");
    // load the function from the script
    PyObject *pythonName = PyString_FromString(pythonFileName);
    PyObject *pythonModule = PyImport_Import(pythonName);
    Py_DECREF(pythonName);
    PyObject *pythonFunc = PyObject_GetAttrString(pythonModule, functionName);
    if (!isCallable(functionName, pythonFunc))
        exit(-1);
    // Create data which will be passed to the python's function.
    // Because the numbers of the argument is 2, the python's function must receive 2 arguments (see the script file).
    int pythonFuncArgNum = 2;
    PyObject *pythonArgs = PyTuple_New(pythonFuncArgNum);
    // Create the first argument.
    int dataNum = 3;
    int channelNum = 2;
    int measurementNum = 4;
    PyObject *params = PyList_New(3);
    PyList_SET_ITEM(params, 0, PyInt_FromLong(dataNum));
    PyList_SET_ITEM(params, 1, PyInt_FromLong(channelNum));
    PyList_SET_ITEM(params, 2, PyInt_FromLong(measurementNum));
    PyTuple_SetItem(pythonArgs, 0, params); // Set the first argument.
    // Create the second argument.
    PyObject *datas = PyTuple_New(dataNum);
    for (int i = 0; i < dataNum; i++) {
        PyObject *data = PyTuple_New(channelNum);
        PyObject *channel0 = PyList_New(measurementNum);
        PyObject *channel1 = PyList_New(measurementNum);
        for (int j = 0; j < measurementNum; j++) {
            PyList_SET_ITEM(channel0, j, PyFloat_FromDouble(i + j * 2.0));
            PyList_SET_ITEM(channel1, j, PyFloat_FromDouble(i * 2.0 + j * 2.0));
        }
        PyTuple_SetItem(data, 0, channel0);
        PyTuple_SetItem(data, 1, channel1);
        PyTuple_SetItem(datas, i, data);
    }
    PyTuple_SetItem(pythonArgs, 1, datas); // Set the second argument.
    // Call the python's function and print the returned values.
    PyObject *pythonValue = PyObject_CallObject(pythonFunc, pythonArgs);
    Py_DECREF(pythonArgs);
    std::cout << "Print the results returned from the python function in the C++ source code." << std::endl;
    for (int i = 0; i < (int)PyList_Size(pythonValue); i++)
        std::cout << i << " , " << PyFloat_AsDouble(PyList_GetItem(pythonValue, i)) << std::endl;
    return 0;
}
python
script.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import numpy as np
print 'Scripts written in outside of python functions will be called when this script is loaded by the C++ source code.\n'
# The function must have 2 arguments because the C++ source code gives the function 2 arguments.
def test_func(params, datas):
    print 'Start the python function.'
    # Copy the parameters.
    data_num = params[0]
    channel_num = params[1]
    measurement_num = params[2]
    print 'data_num =', data_num, ', channel_num =', channel_num, ', measurement_num =', measurement_num
    # Print the second arguments
    for i in range(data_num):
        for j in range(measurement_num):
            print 'i =', i, ', channel0 =', datas[i][0][j], ', channel1 =', datas[i][1][j]
    # Create a dummy result and return it.
    values = []
    for i in range(data_num):
        values.append(i * 3.0)
    print 'The python function will return an array (vector) data.\n'
    return values
g++ main.cpp -o call_py_func_from_c -L/usr/lib/python2.7 -lpython2.7 -I/usr/include/python2.7
Please change the python version and path accordingly.
Place the C / C ++ and python files in the same directory and run them there (because script.py cannot be found unless the python path is set). In the C / C ++ source code, there is a process to set the current directory to the python path.
Scripts written in outside of python functions will be called when this script is loaded by the C++ source code.
Start the python function.
data_num = 3 , channel_num = 2 , measurement_num = 4
i = 0 , channel0 = 0.0 , channel1 = 0.0
i = 0 , channel0 = 2.0 , channel1 = 2.0
i = 0 , channel0 = 4.0 , channel1 = 4.0
i = 0 , channel0 = 6.0 , channel1 = 6.0
i = 1 , channel0 = 1.0 , channel1 = 2.0
i = 1 , channel0 = 3.0 , channel1 = 4.0
i = 1 , channel0 = 5.0 , channel1 = 6.0
i = 1 , channel0 = 7.0 , channel1 = 8.0
i = 2 , channel0 = 2.0 , channel1 = 4.0
i = 2 , channel0 = 4.0 , channel1 = 6.0
i = 2 , channel0 = 6.0 , channel1 = 8.0
i = 2 , channel0 = 8.0 , channel1 = 10.0
The python function will return an array (vector) data.
Print the results returned from the python function in the C++ source code.
0 , 0
1 , 3
2 , 6
I passed the value calculated in C / C ++ to the python function, and made a program to return the processing performed in the python function to C / C ++.
He says, "I know there are good libraries (deep learning, etc.) in python, but I don't like writing all programs in python" (I can't keep up with new ones ...). So, I basically wrote it in C / C ++ and thought it would be nice to be able to call the python library only when needed.
I think there are already similar pages, but to make sure I don't forget ...
Recommended Posts