通过C API从字符串创建和调用python函数

ala*_*10n 12 c python embed

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

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


编辑:

在开启后我找到了这个解决方案PyRun_String.我正在创建一个新模块,获取它的字典对象,在调用时传递它以PyRun_String在我的新模块中定义一个函数,然后为新创建的函数获取一个函数对象并PyObject_CallObject通过我的args 调用它.这是我发现解决我的问题: 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;
}
Run Code Online (Sandbox Code Playgroud)

这是我原帖的其余部分,留给后人:

这是我最初做的事情 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;
}
Run Code Online (Sandbox Code Playgroud)

而且atest.py:


def doStuff( x):
    print "X is %d\n" % x
    return 2 * x
Run Code Online (Sandbox Code Playgroud)

Tam*_*más 6

PyRun_String在Python C API中可能正是您正在寻找的.请参阅:http://docs.python.org/c-api/veryhigh.html

  • 目前尚不清楚我如何将参数传递给该函数。看起来我确实可以使用“PyRun_String”定义一个函数,但我不知道如何使用不仅仅是硬编码字符串的参数来调用它。也就是说,我可以使用“doStuff(7)”作为第一个参数再次调用 PyRun_String,但如果参数是一个对象或类似的东西,那么这将不起作用。如果 doStuff 是通过 PyRun_String 定义的,是否有某种方法可以调用 PyObject_GetAttrString 来获取 doStuff 的函数对象? (2认同)
  • 抱歉,最近几个小时我没有上线,但看来您完全想通了。`PyRun_String`从一个字符串中运行一个Python代码块,并返回该代码将返回的内容-我猜在您的情况下,它为`None'。之后,您刚刚评估的函数将添加到本地名称空间中-您必须使用`PyObject_GetAttrString`从那里检索它,然后调用它。您可能还需要检查`PyRun_String`的返回值-如果它为`NULL`,则在执行代码块时发生异常。 (2认同)

kmp*_*kmp 5

问题中包含的答案非常好,但是我将它与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;
}
Run Code Online (Sandbox Code Playgroud)