Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call Python from C++

Tags:

c++

python

c

I'm trying to call a function in a Python script from my main C++ program. The python function takes a string as the argument and returns nothing (ok.. 'None'). It works perfectly well (never thought it would be that easy..) as long as the previous call is finished before the function is called again, otherwise there is an access violation at pModule = PyImport_Import(pName).

There are a lot of tutorials how to embed python in C and vice versa but I found nothing about that problem.

int callPython(TCHAR* title){
    PyObject *pName, *pModule, *pFunc;
    PyObject *pArgs, *pValue;

Py_Initialize();
    pName = PyUnicode_FromString("Main");
    /* Name of Pythonfile */

    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, "writeLyricToFile");
        /* function name. pFunc is a new reference */
        if (pFunc && PyCallable_Check(pFunc)) {
            pArgs = PyTuple_New(1);

    pValue = PyUnicode_FromWideChar(title, -1);

    if (!pValue) {
        Py_DECREF(pArgs);
                Py_DECREF(pModule);
        showErrorBox(_T("pValue is false"));
        return 1;
            }
    PyTuple_SetItem(pArgs, 0, pValue);

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

            if (pValue != NULL) {
                //worked as it should!
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
        showErrorBox(_T("pValue is null"));
        return 1;
            }
        }
        else {
            if (PyErr_Occurred()) PyErr_Print();
            showErrorBox(_T("pFunc null or not callable"));
        return 1;
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        showErrorBox(_T("pModule is null"));
    return 1;
    }
    Py_Finalize();
    return 0;
}
like image 754
Voo Avatar asked Sep 13 '09 11:09

Voo


People also ask

Can I call a Python function in C?

A reference to an existing Python callable needs to be passed in, to use this function. To do that there are many ways like – simply writing C code to extract a symbol from an existing module or having a callable object passed into an extension module.

How do you call a Python file from C program?

The first step towards embedding Python in C is to initialize Python interpreter, which can be done with the following C function. Py_Initialize(); After the interpreter is initialized, you need to set the path to the Python module you would like to import in your C program.

How do I connect Python to C?

There a number of ways to do this. The rawest, simplest way is to use the Python C API and write a wrapper for your C library which can be called from Python. This ties your module to CPython. The second way is to use ctypes which is an FFI for Python that allows you to load and call functions in C libraries directly.

How do I call a Python file from command line?

To run Python scripts with the python command, you need to open a command-line and type in the word python , or python3 if you have both versions, followed by the path to your script, just like this: $ python3 hello.py Hello World! If everything works okay, after you press Enter , you'll see the phrase Hello World!


2 Answers

When you say "as long as the previous call is finished before the function is called again", I can only assume that you have multiple threads calling from C++ into Python. The python is not thread safe, so this is going to fail!

Read up on the Global Interpreter Lock (GIL) in the Python manual. Perhaps the following links will help:

  • http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock
  • http://docs.python.org/c-api/init.html#PyEval_InitThreads
  • http://docs.python.org/c-api/init.html#PyEval_AcquireLock
  • http://docs.python.org/c-api/init.html#PyEval_ReleaseLock

The GIL is mentioned on Wikipedia:

  • http://en.wikipedia.org/wiki/Global_Interpreter_Lock
like image 179
Daniel Paull Avatar answered Oct 18 '22 20:10

Daniel Paull


Thank you for your help!

Yes you're right, there are several C threads. Never thought I'd need mutex for the interpreter itself - the GIL is a completly new concept for me (and isn't even once mentioned in the whole tutorial).

After reading the reference (for sure not the easiest part of it, although the PyGILState_* functions simplify the whole thing a lot), I added an

void initPython(){
    PyEval_InitThreads();
    Py_Initialize();
    PyEval_ReleaseLock();
}

function to initialise the interpreter correctly. Every thread creates its data structure, acquires the lock and releases it afterwards as shown in the reference.

Works as it should, but when calling Py_Finalize() before terminating the process I get a segfault.. any problems with just leaving it?

like image 1
Voo Avatar answered Oct 18 '22 18:10

Voo