Создание и вызов функции python из строки через C API

можно ли загрузить функцию python из строки, а затем вызвать эту функцию с аргументами и получить возвращаемое значение?

я использую API python C для запуска кода python из моего приложения c++. Я могу загрузить модуль из файла, используя PyImport_Import, получить объект функции, что с помощью PyObject_GetAttrString, и вызовите функцию с PyObject_CallObject. Что я хотел бы сделать, так это загрузить модуль / функцию из строки вместо файла. Есть ли какой-то эквивалент PyImport_Import что позволит мне передать ему строку вместо файла? Мне нужно передать аргументы вызываемой функции, и мне нужен доступ к возвращаемому значению, поэтому я не могу просто использовать PyRun_SimpleString.


Edit:

я нашел это решение после включения 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):ntprint 5 * xntreturn 77n", 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: %ldn", 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 nulln");
        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: %ldn", PyInt_AsLong(pValue));
    Py_DECREF(pValue);

    Py_XDECREF(pFunc);
    Py_DECREF(pModule);

    Py_Finalize();

    return 0;
}

и atest.py:


def doStuff( x):
    print "X is %dn" % x
    return 2 * x

2 ответов


PyRun_String в Python C API, вероятно, то, что вы ищете. Смотри:http://docs.python.org/c-api/veryhigh.html


ответ, содержащийся в вопросе, отличный, но у меня были небольшие проблемы с его использованием с 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;
}