2010-09-24 100 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; 
}