Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create and call python function from string via C API

Tags:

python

c

embed

Is it possible to load a python function from a string and then call that function with arguments and get the return value?

I'm using the python C API to run python code from inside my C++ application. I'm able to load a module from a file using PyImport_Import, get a function object from that using PyObject_GetAttrString, and call the function with PyObject_CallObject. What I'd like to do is to load the module/function from a string instead of a file. Is there some equivalent to PyImport_Import which would allow me to pass it a string instead of a file? I need to pass arguments to the function I'm calling and I need access to the return value, so I can't just use PyRun_SimpleString.


Edit:

I found this solution after getting turned on to PyRun_String. I'm creating a new module, getting its dictionary object, passing that along in a call to PyRun_String to define a function in my new module, then getting a function object for that newly created function and calling it via PyObject_CallObject, passing my args. This is what I've found to solve my problem: main.cpp


int main()
{
    PyObject *pName, *pModule, *pArgs, *pValue, *pFunc;
    PyObject *pGlobal = PyDict_New();
    PyObject *pLocal;

    //Create a new module object
    PyObject *pNewMod = PyModule_New("mymod");

    Py_Initialize();
    PyModule_AddStringConstant(pNewMod, "__file__", "");

    //Get the dictionary object from my module so I can pass this to PyRun_String
    pLocal = PyModule_GetDict(pNewMod);

    //Define my function in the newly created module
    pValue = PyRun_String("def blah(x):\n\tprint 5 * x\n\treturn 77\n", Py_file_input, pGlobal, pLocal);
    Py_DECREF(pValue);

    //Get a pointer to the function I just defined
    pFunc = PyObject_GetAttrString(pNewMod, "blah");

    //Build a tuple to hold my arguments (just the number 4 in this case)
    pArgs = PyTuple_New(1);
    pValue = PyInt_FromLong(4);
    PyTuple_SetItem(pArgs, 0, pValue);

    //Call my function, passing it the number four
    pValue = PyObject_CallObject(pFunc, pArgs);
    Py_DECREF(pArgs);
    printf("Returned val: %ld\n", PyInt_AsLong(pValue));
    Py_DECREF(pValue);

    Py_XDECREF(pFunc);
    Py_DECREF(pNewMod);
    Py_Finalize();

    return 0;
}

Here is the rest of my original post, left for posterity:

Here's what I was doing originally: main.cpp:


#include <Python.h>

int main()
{
    PyObject *pName, *pModule, *pArgs, *pValue, *pFunc;

    Py_Initialize();
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('')");
    pName = PyString_FromString("atest");
    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if(pModule == NULL)
    {
        printf("PMod is null\n");
        PyErr_Print();
        return 1;
    }

    pFunc = PyObject_GetAttrString(pModule, "doStuff");
    pArgs = PyTuple_New(1);
    pValue = PyInt_FromLong(4);
    PyTuple_SetItem(pArgs, 0, pValue);

    pValue = PyObject_CallObject(pFunc, pArgs);
    Py_DECREF(pArgs);
    printf("Returned val: %ld\n", PyInt_AsLong(pValue));
    Py_DECREF(pValue);

    Py_XDECREF(pFunc);
    Py_DECREF(pModule);

    Py_Finalize();

    return 0;
}

And atest.py:


def doStuff( x):
    print "X is %d\n" % x
    return 2 * x
like image 728
alanc10n Avatar asked Sep 24 '10 18:09

alanc10n


People also ask

Can I call a Python function in C?

We can call a C function from Python program using the ctypes module.

What is PyEval_EvalFrameEx?

Running functions Almost the entire Python interpreter can be summarized into one C-level function: PyEval_EvalFrameEx. This function is the interpreter loop. Consisting of 3k lines of code, its job is to evaluate a frame, or in other words, run it.

What is C API in Python?

The Python/C API allows for compiled pieces of code to be called from Python programs or executed within the CPython interpreter. This process of producing compiled code for use by CPython is generally known as "extending" Python and the compiled pieces of code to be used are known as "extension modules".


1 Answers

PyRun_String in the Python C API is probably what you're looking for. See: http://docs.python.org/c-api/veryhigh.html

like image 83
Tamás Avatar answered Oct 27 '22 13:10

Tamás