2010-09-24 58 views
9

是否可以从字符串加载python函数,然后使用参数调用该函数并获取返回值?通过C API从字符串创建并调用python函数

我正在使用python C API从我的C++应用程序中运行python代码。我可以使用PyImport_Import从文件加载模块,使用PyObject_GetAttrString从中获取函数对象,然后使用PyObject_CallObject调用该函数。我想要做的是从字符串而不是文件加载模块/函数。是否有一些相当于PyImport_Import这将允许我传递一个字符串而不是文件?我需要传递参数给我打电话的函数,我需要访问返回值,所以我不能只使用PyRun_SimpleString


编辑:

我发现刚刚开始了解PyRun_String后,这一解决方案。我正在创建一个新模块,获取其字典对象,并在调用PyRun_String时将其传递给我的新模块中的一个函数,然后为该新创建的函数获取一个函数对象,并通过PyObject_CallObject调用它,传递我的参数。这是我找到了解决我的问题: 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; 
} 

这是我原来的职位的休息,为后人留下了:

这里就是我最初做: 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; 
} 

而且atest.py


def doStuff(x): 
    print "X is %d\n" % x 
    return 2 * x 
+0

这是没有必要离开你的职位后代。堆栈溢出已涵盖。所有对问题和答案的编辑都会自动存档,一旦我们的积分达到一定水平,我们就可以看到。这有助于我们回滚不良编辑,并追踪更改以更好地理解问题。所以,不要把它放在那里,你可以删除你的改变,如果需要的话,我们可以看看编辑日志。因此,甚至没有必要输入“编辑:”。 – 2015-01-14 20:02:55

回答

5

PyRun_String在Python C API中可能是你正在寻找的东西。见:http://docs.python.org/c-api/veryhigh.html

+1

我不清楚如何将参数传递给函数。它看起来像我可以使用'PyRun_String'定义一个函数,但是我看不到如何用不仅仅是硬编码字符串的参数来调用它。也就是说,我可以再次用“doStuff(7)”作为第一个参数来调用PyRun_String,但如果参数是一个对象或类似的东西,那将不起作用。如果PyObject_GetAttrString已经通过PyRun_String定义了,有没有办法调用PyObject_GetAttrString来获取doStuff的函数对象? – alanc10n 2010-09-24 20:57:13

+0

接受,因为它启动了我寻找解决方案的途径,尽管我必须做一个阅读的时间才能到达目的地。谢谢。 – alanc10n 2010-09-24 21:55:00

+1

对不起,在过去的几个小时里,我并没有上网,但看起来你已经准确无误地计算出来了。'PyRun_String'从一个字符串运行一段Python代码,并返回代码将返回的任何内容 - 我认为它是'None'。之后,您刚刚评估的函数将添加到本地名称空间 - 您必须使用“PyObject_GetAttrString”从那里检索它,然后调用它。您可能还想检查'PyRun_String'的返回值 - 如果它是'NULL',执行代码块时出现异常。 – 2010-09-24 22:33:37

3

问题中包含的答案很好,但我有一些小的麻烦,使用它与Python 3.5,所以为了节省任何人做我做的,下面是一个稍微编辑的版本,似乎这个版本工作得很好的Python至少:

#include <Python.h> 

int main(void) 
{ 
    PyObject *pArgs, *pValue, *pFunc, *pModule, *pGlobal, *pLocal; 

    Py_Initialize(); 

    pGlobal = PyDict_New(); 

    //Create a new module object 
    pModule = PyModule_New("mymod"); 
    PyModule_AddStringConstant(pModule, "__file__", ""); 

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

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

    //pValue would be null if the Python syntax is wrong, for example 
    if (pValue == NULL) { 
     if (PyErr_Occurred()) { 
      PyErr_Print(); 
     } 
     return 1; 
    } 

    //pValue is the result of the executing code, 
    //chuck it away because we've only declared a function 
    Py_DECREF(pValue); 

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

    //Double check we have actually found it and it is callable 
    if (!pFunc || !PyCallable_Check(pFunc)) { 
     if (PyErr_Occurred()) { 
      PyErr_Print(); 
     } 
     fprintf(stderr, "Cannot find function \"blah\"\n"); 
     return 2; 
    } 

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

    //Call my function, passing it the number four 
    pValue = PyObject_CallObject(pFunc, pArgs); 

    fprintf(stdout, "Returned value: %ld\n", PyLong_AsLong(pValue)); 

    Py_DECREF(pValue); 
    Py_XDECREF(pFunc); 

    Py_Finalize(); 

    return 0; 
}