简体   繁体   中英

C++ and Boost.Python - how to expose variable to python and update it in loop?

Introduction

I have a python code called from c++, using boost.python package. I can pass some variables, when calling MyFunc from .py like this:

Py_SetPythonHome(pySearchPath);
try
{
Py_Initialize();
numpy::initialize();
object module = import("__main__");
object name_space = module.attr("__dict__");
exec(python_full, name_space, name_space);
object MyFunc = name_space["MyFunc"];

object result = MyFunc(var1, var2, var3)); //HERE

//Python results storage
numpy::ndarray ret = extract<numpy::ndarray>(result);
int input_size = ret.shape(0);
std::vector<std::vector<double>> v(input_size, std::vector<double>(50));
}
catch (error_already_set)
{
    PyErr_Print();
}

However I need another variable, lets call it var4 , to be updated, basing on C++ GUI, on every loop of my python code. If I understand correctly MyFunc(var1, var2, var3) pass the value only once, at the beginning, so even if i change the value of var1 after executing it, it will not affect python code.

The problem

Is there any way, to expose c++ variable, so it will be updated "live" in python code? If all would be in one language it will be trivial (with global variables for example), but on the edge of two environment it becomes tricky.

Edit:

I was trying to expose variable gui_cancel like this:

BOOST_PYTHON_MODULE(cbtest)
{
    class_<callback_handler, boost::noncopyable>("callback_handler", no_init)
        .def_readwrite("gui_cancel", &callback_handler::gui_cancel);
        ;
};

But accessing it from python this way:

import cbtest
holder = cbtest.callback_handler
print(holder.gui_cancel)

Give me only the property of the object:

<property object at 0x0000012D9AA90BD8>

I don't know how you would expose a variable directly, but you can always expose a C function, and have that C function return the current value of the variable to the Python script when the Python script calls it.

Below is an example C program that demonstrates the technique. Note that main() runs a simple Python script that calls the included C function GetRandomNumber() . GetRandomNumber() chooses a random number and prints its value to stdout, and then returns it to the Python script. The Python script then prints out the value as well, so you can verify that the Python code printed the same value that the C code chose.

#include <Python.h>
#include <stdio.h>

static PyObject * GetRandomNumber(PyObject * pyObj, PyObject * args, PyObject * keywords)
{
   const int randomNumber = rand();
   printf("C Function GetRandomNumber():  I choose:  %i\n", randomNumber);
   return PyLong_FromLong(randomNumber);
}

static PyMethodDef DemoEditorMethods[] = {
   {"GetRandomNumber", (PyCFunction)GetRandomNumber, METH_KEYWORDS | METH_VARARGS, "Returns a random integer."},
   {NULL, NULL, 0, NULL}  // list terminator
};

PyDoc_STRVAR(demo_doc, "This module is just here to demonstrate calling a C function from Python and having it return a value.");

static struct PyModuleDef DemoModuleDefinition = {
   PyModuleDef_HEAD_INIT,
   "embedded_demo",
   demo_doc,
   -1,
   DemoEditorMethods,
   NULL,
   NULL,
   NULL,
   NULL
};

int main(int argc, char *argv[])
{
    Py_Initialize();

    // Note:  if this line is causing you link errors under Windows,,
    // try rebuilding pythoncore.lib in "Release Mode" instead of
    // "Debug mode".
    PyObject * csMod = PyModule_Create(&DemoModuleDefinition);
    if (csMod)
    {
       PyObject *modules = PyImport_GetModuleDict();
       if (modules)
       {
          PyObject * nameObj = PyUnicode_FromString("embedded_demo");
          if ((nameObj == NULL)||(PyObject_SetItem(modules, nameObj, csMod) != 0)) printf("PyObject_SetItem() failed!?\n");
       }
       else printf("PyImport_GetModuleDict() returned NULL!\n");
    }
    else printf("Unabled to create embedded_demo Python module!\n");

    if (PyImport_ImportModule("embedded_demo") == NULL) printf("Unable to import embedded_demo Python module!\n");

    PyRun_SimpleString(
        "import sys;"
        "import embedded_demo;"
        "v = embedded_demo.GetRandomNumber();"
        "print('Python Script:  The random value I got from the C GetRandomNumber() function is: %i' % v);"
    );
    Py_Finalize();
    return 0;
}

When I run the above program, I see this output:

$ ./test_c_function_call
C Function GetRandomNumber():  I choose:  16807
Python Script:  The random value I got from the C GetRandomNumber() function is: 16807

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM