Thursday, December 27, 2012

Calling Python Module from C

This is a sample function (modified from python docs) to call python function in a python module from C language:
/** \brief This function executes python module passed in args[0]
 * 
 * \param argCount number of arguments passed to this function in args parameter
 * \param args array of string containing the parameters. The first parameter is 
 *     the name of the python module, the second parameter is the  
 *     function name in the python module. The third and latter parameters
 *     are the parameters to the python function in the python module.
 */
int
exec_python_module(int argCount, char *args[])
{
    PyObject *pName, *pModule, *pDict, *pFunc;
    PyObject *pArgs, *pValue, *pFloatValue;
    int i;

    if (argCount < 2) {
        fprintf(stderr,"exec_python_module() usage: pythonfile funcname [args]\n");
        return 1;
    }

    Py_Initialize();
    pName = PyString_FromString(args[0]);
    /* Error checking of pName left out */

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

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, args[1]);
        /* pFunc is a new reference */

        if (pFunc && PyCallable_Check(pFunc)) {
   /* NOTE: The function parameters start at 
      args[2], that's why the index must be 
      subtracted with two below */
            pArgs = PyTuple_New(argCount - 2);
            for (i = 0; i < argCount - 2; ++i) {
                pValue = PyString_FromString(args[i + 2]); 
  
                if (!pValue) {
                    Py_DECREF(pArgs);
                    Py_DECREF(pModule);
                    fprintf(stderr, "Cannot convert argument\n");
                    return 1;
                }
                /* pValue reference stolen here: */
  PyTuple_SetItem(pArgs, i, pValue);
            }
            pValue = PyObject_CallObject(pFunc, pArgs);
            Py_DECREF(pArgs);
            if (pValue != NULL) {
                printf("Result of call: %ld\n", PyInt_AsLong(pValue));
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr,"Call failed\n");
                return 1;
            }
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function \"%s\"\n", args[1]);
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"%s\" module\n", args[0]);
        return 1;
    }
    Py_Finalize();
    return 0;
}
The main difference to the sample code in python 2.7.3 docs (section  Embedding Python in Another Application | Pure Embedding) is that instead of PyInt_FromLong(), I'm using PyString_FromString() function. Therefore, the assumption is that all of the function arguments are passed as string, in order not to truncate anything.
It's the job of the python function to convert to the right type as needed. For example, if you pass float value as string then you have to convert the float string to float in your python code. Let's see how to do this. Take a look at the python function as follows:
def My_Function(my_float_string_param):
    converted_float = float(my_float_string_param)
## Process using float here
## ...
The python code above converts the float string into float with the float() function. This is needed, otherwise the python interpreter would balk out with error message if you use my_float_string_param directly on function calls that expects a python float variable. Instead of using my_float_string_param, you should use converted_float in those function calls.
Post a Comment

No comments: