通过C API从字符串创建并调用Python函数[英] Create and call python function from string via C API

本文是小编为大家收集整理的关于通过C API从字符串创建并调用Python函数的处理方法,想解了通过C API从字符串创建并调用Python函数的问题怎么解决?通过C API从字符串创建并调用Python函数问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

是否可以从字符串加载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;
}

这是我原始帖子的其余部分,剩下的后代:

这是我最初在做的事情: 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

推荐答案

PyRun_String在Python C API中可能是您​​想要的.请参阅: a>

其他推荐答案

问题中包含的答案非常好,但是我使用 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;
}

其他推荐答案

这个问题很旧,但是,如果有人仍在尝试弄清楚这一点(就像我一样),我会提供我的答案.

@kmp工作的原始答案和更新的答案可用于简单示例,但是当将import语句介绍到代码中时,这是不起作用的.

我在这里找到了一个有效的示例: https://WASU.com/weblog/embedding-python/writing-a-c-wrapper-library-part3/

简称(使用Python 3.6 API):

  • 阅读以下内容的python文件:
std::string line, text;
std::ifstream in("the_file.py");
while (std::getline(in, line)) {
  text += line + "\n";
}
const char *data = text.c_str();
  • 将其编译为字节:
PyObject *pCodeObj = Py_CompileString(data, "", Py_file_input);
  • 通过执行代码来创建模块:
pModule = PyImport_ExecCodeModule("the_module", pCodeObj );

然后,您可以通过使用PyObject_GetAttrString获得功能并在上面的示例中调用它们来继续.

本文地址:https://www.itbaoku.cn/post/359331.html