Нахождение параметров функции Python из C ++ - PullRequest
4 голосов
/ 07 июля 2011

Я вызываю функции Python из C ++.Мне было интересно, можно ли определить количество параметров и названия этих параметров.Я прочитал ссылку Как найти число параметров для функции Python из C? , однако я не совсем понимаю.

У меня есть эта функция C ++, которая вызывает функцию «добавить»из pyFunction.py.add добавляет два параметра и возвращает сумму.

static float CallPythonFunc( float *parameters )
{
    PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pArgs;
    float ret;

    // Initialize the python interpreter
    Py_Initialize();

    // Make sure we are getting the module from the correct place
    // ### This is where we will put the path input
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\"/Developer/IsadoraSDK/IsadoraDemoMathFunction/\")");

    // Build the name object
    // ### This is where we will put the function input
    pName = PyString_FromString("pyFunction");

    // Load the module object
    pModule = PyImport_Import(pName);

    // pDict is a borrowed reference
    pDict = PyModule_GetDict(pModule);

    // pFunc is a borrowed reference
    pFunc = PyDict_GetItemString(pDict, "add");

    //
    // Somehow get the number of arguments and possible the arguments names from 'add'
    //

    if (PyCallable_Check(pFunc)) 
    {       
        // Set the number of arguments
                // This is where I would like to pass in number of arguments
        pArgs = PyTuple_New( 2 /*number of arguments*/ );

        //
        // Instead of the following if I had the arguments I could loop through them
        // and pass the correct number in
        //

        // Argument 1
        pValue = PyFloat_FromDouble((double)parameters[0]);
        PyTuple_SetItem(pArgs, 0, pValue);

        // Argument 2
        pValue = PyFloat_FromDouble((double)parameters[1]);
        PyTuple_SetItem(pArgs, 1, pValue);

            // Make the call to the function
        pValue = PyObject_CallObject(pFunc, pArgs);

        // Set return value
        ret = (float)PyFloat_AsDouble(pValue);

        // Clean up
        Py_DECREF(pArgs);
        Py_DECREF(pValue);
    }

// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);

// Finish the Python Interpreter
Py_Finalize();

return ret;
}

Я действительно не очень знаком с C / C ++, поэтому любая помощь будет очень полезна.Спасибо всем за уделенное время!

РЕДАКТИРОВАТЬ: Так что-то вроде следующего?

PyObject *tuple, *arglist;
tuple = PyObject_CallMethod(pFunc,"inspect.getargspec","add");
arglist = PyTuple_GetItem(tuple,0);
int size = PyObject_Size(arglist);

1 Ответ

4 голосов
/ 08 июля 2011

Этот ответ на вопрос, который вы связали с , кажется, вам нужен. inspect.getargspec делает именно то, что вы хотите на стороне Python, и, как говорится в ответе, вы можете использовать PyObject_CallMethod или одну из связанных функций, описанных в этой цели ссылки, для вызова inspect.getargspec из вашего кода C ++, получить возвращенный кортеж как PyObject, использовать PyTuple_GetItem(returned_tuple, 0), чтобы получить список аргументов, а затем использовать либо PyObject_Size(), либо PyObject_Length() в списке, чтобы получить количество аргументов. Вы также захотите проверить второй и третий элементы возвращенного кортежа и увеличить число аргументов на 1 для каждого из двух, отличных от Py_None. Посмотрите приведенный ниже фрагмент кода, почему.

>>> import inspect
>>> def testfunc(a, b, c, *d, **e):
    pass

>>> inspect.getargspec(testfunc)
ArgSpec(args=['a', 'b', 'c'], varargs='d', keywords='e', defaults=None)
<ч />

Вот пример того, что вы должны сделать (не все возможные ошибки могут быть проверены, но это должны быть все проверки NULL, которые могут потребоваться):

PyObject *pName, *pInspect, *argspec_tuple, *arglist;
int size;

pName = PyString_FromString("inspect");

if (pName)
{
    pInspect = PyImport_Import(pName);
    Py_DECREF(pName);


    if (pInspect)
    {
        pName = PyString_FromString("getargspec");

        if (pName)
        {
            argspec_tuple = PyObject_CallMethodObjArgs(pInspect, pName, pFunc, NULL);
            Py_DECREF(pName);

            if (argspec_tuple)
            {
                arglist = PyTuple_GetItem(argspec_tuple, 0);

                if (arglist)
                {
                    size = PyObject_Size(arglist)
                         + (PyTuple_GetItem(argspec_tuple, 1) == Py_None ? 0 : 1)
                         + (PyTuple_GetItem(argspec_tuple, 2) == Py_None ? 0 : 1);  // Haven't actually tested this, but it should work
                }
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...