2011-07-07 69 views
3

我从C++调用python函数。我想知道是否可以确定参数的数量和这些参数的名称。我已阅读链接How to find the number of parameters to a Python function from C?,但我不太明白。从C++中查找python函数参数

我有这个C++函数,它调用pyFunction.py函数'add'。 '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); 

回答

4

This answer to the question you linked to似乎是你想要的。 inspect.getargspec完全符合你想要的Python方面,并且如答案所述,可以使用PyObject_CallMethod或该链接目标中描述的相关函数之一从C++代码调用inspect.getargspec,将返回的元组作为PyObject,使用PyTuple_GetItem(returned_tuple, 0)获取参数列表,然后使用列表上的PyObject_Size()PyObject_Length()来获取参数的数量。您还需要检查返回的元组的第二个和第三个元素,并将两个不是Py_None的每个元素的参数个数增加1。查看下面的代码片段为什么。

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

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

下面是你应该做的(不是所有可能的错误,可以检查,但它应该是所有空的检查可能是必要的)一个例子:

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 
       } 
      } 
     } 
    } 
} 
+0

谢谢你的回应。我还编辑了我的帖子,提供了一个后续问题 – konbanwa

+0

除了你在编辑中的内容之外,你还需要包含像'size + =(PyTuple_GetItem(tuple,1)== Py_None?0:1)+ PyTuple_GetItem(tuple,2)== Py_None?0:1);'来说明'*'和'**'参数的可能性。 (如果你不认识使用的语法,它被称为三元运算符,类似于在线的'if ... else'语句。) – JAB

+0

哦,实际上,请检查我的更新答案,以了解您可能想要执行的操作。 – JAB