Search code examples
pythonc++cvisual-studio-2010cpython

Refreshing a import in C embedded python


I have a C code which has embedded python in it using "Python.h" It works fine without any errors - But it doesn't completely do what I want it to.

What it does : After the C code starts running, it ignores all changes which I make to the python file until I restart the C code.

What I want : While the C code is running, if i make changes to the python file, it should start running the new code.

I tried using the function PyImport_ReloadModule in everytime before calling the function, but it does not work. Am I doing something wrong ?

My current code :

#include "Strategy.h"
#undef _DEBUG /* Link with python24.lib and not python24_d.lib */
#include <Python.h>
#include <stdlib.h>
#include <iostream>

using namespace std;
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;

void import_py() {
    pName = PyString_FromString("main");
    pModule = PyImport_Import(pName);
    Py_DECREF(pName);
    if (pModule == NULL) {
        cout << "ERR : Unable to load main.py\n";
        return;
    } else {
        cout << "OK : Loaded main.py\n";
    }
    if ( PyObject_HasAttrString(pModule, "main") ) {
        cout << "OK : main.py has function main\n";
    } else {
        cout << "ERR : main.py has no function main\n";
        return;
    }
    pFunc = PyObject_GetAttrString(pModule, "main");
    if ( pFunc == NULL ) {
        cout << "OK : main.py's function main gave NULL when trying to take it\n";
        return;
    }
}

void remove_py() {  
    Py_XDECREF(pArgs);
    Py_XDECREF(pModule);
    Py_XDECREF(pFunc);
    Py_Finalize();
}

void Construct() {
    Py_Initialize();
    import_py();
}

void Destruct() {
    if ( pModule || pFunc ) {
        remove_py();
    }
}


void Loop () {
    if ( ! ( pModule && pFunc ) ) {
        cout << "Looped. But python values are null\n";
        return;
    }
    cout << "Loop : ";

    pArgs = PyTuple_New(2); // Create a tuple to send to python - sends 1,2
    PyTuple_SetItem(pArgs, 0, PyInt_FromLong(1));
    PyTuple_SetItem(pArgs, 1, PyInt_FromLong(2));

    pValue = PyObject_CallObject(pFunc, pArgs);
    Py_DECREF(pArgs);

    double t = 0; // Get the 2 return values
    t = PyFloat_AsDouble(PyTuple_GetItem(pValue, 0));
    cout << t << ", ";
    t = PyFloat_AsDouble(PyTuple_GetItem(pValue, 1));
    cout << t;

    cout << "\n";
}

void main() {
    Construct();
    while(1) { // Using an infinite loop for now - to test
        pModule = PyImport_ReloadModule(pModule);
        Loop();
    }
    Destruct();
}

Solution

  • I found the issue.

    Even after getting the new module with pModule = PyImport_ReloadModule(pModule) the p variable pFunc doesn't get automatically updated. So, the variable pFunc is still referencing the old module !

    hence, every variable needs to be got again. Like so :

    void main() {
        Construct();
        while(1) { // Using an infinite loop for now - to test
            pModule = PyImport_ReloadModule(pModule);
            pFunc = PyObject_GetAttrString(pModule, "main");
            Loop();
        }
        Destruct();
    }
    

    One thing I am not sure about here is whether DECREF should be made to the pFunc which is referencing the old pModule.