Python C++ API - 具有可变数量参数的重载函数

Posted

技术标签:

【中文标题】Python C++ API - 具有可变数量参数的重载函数【英文标题】:Python C++ API - overloading functions with variable number of arguments 【发布时间】:2019-05-21 16:09:43 【问题描述】:

我正在尝试重载以下 sayHi 函数,该函数旨在接收 char* 作为输入参数,或者, 或者,一个 char* 和一个整数。

它是 Box 类的一部分(它本身用于定义 python 对象 PyBox):

class Box 
   public:

   Box();

   void sayHi(char *name);

   void sayHi(char *name, int number);
   ;

在我的包装器中,我定义了以下方法:

static PyObject *pyBox_sayHi_char(PyBox *self, char *Name)

    self->bx->sayHi(Name);

    Py_RETURN_NONE;


static PyObject *pyBox_sayHi_char_int(PyBox *self, char *Name, int number)

        self->bx->sayHi(Name, number);

    Py_RETURN_NONE;


static PyObject *Hi_overload_switch(PyBox *self,  PyObject *args)

    PyObject *x = NULL;
    PyObject *y = NULL;

    if (!PyArg_ParseTuple(args, "|OO", &x, &y))
        return NULL;

    if (PyUnicode_Check(x) && PyLong_Check(y) && y != NULL)
    
        printf("A!\n\n");

        const char* s = PyBytes_AsString(PyUnicode_AsUTF8String(x)); 

        Py_DECREF(x);

        return pyBox_sayHi_char_int(self, s, PyLong_AsLong(y));

    
    else if (PyUnicode_Check(x) && y == NULL)
       
        printf("B!\n\n");

        const char* s = PyBytes_AsString(PyUnicode_AsUTF8String(x)); 

        Py_DECREF(x);

        return pyBox_sayHi_char(self, s);
    
    else
    
        Py_RETURN_NOTIMPLEMENTED;
    

    Py_RETURN_NOTIMPLEMENTED;


static PyMethodDef pyBox_methods[] = 
    "Hi", (PyCFunction)Hi_overload_switch, METH_VARARGS, "Hi",
    NULL, NULL, 0, NULL
;

但是,当我转到 python 3.7 并运行时:

bo.Hi("John", 52364)

bo.Hi("Steve")

它打印第一条语句,但在 Steve 上出现了段错误。有什么建议为什么会这样?

谢谢!

【问题讨论】:

Python 版本? 起来! 3.7 版 - 谢谢;编辑了问题 在您的else if (PyLong_Check(x)) 中,您正在检查long,然后将x 转换为字符串...对吗? 很好看!我已经在问题中更正了,但是结果是一样的! 【参考方案1】:

问题就在这里:

if (!PyArg_ParseTuple(args, "|OO", &x, &y))
    return NULL;

if (PyUnicode_Check(x) && PyLong_Check(y)) ...

您正在使用两个可选参数(如果没有给出参数,PyArg_ParseTuple 不会修改传递的变量)。所以bo.Hi("Steve") 只填充 x,但是你使用 y 而不检查它,因此是段错误。在 y 的初始值上,您一定很幸运能够使用以前的版本。

【讨论】:

谢谢!那么如何检查传递给 Hi 函数的参数数量? 在这种情况下,我会将它们显式设置为 nullptr,然后在调用 PyArg_ParseTuple 后检查它们是否为空 请注意,PyArg_ParseTuple 不会在您需要保留必须自己做的对象时为您增加引用计数。【参考方案2】:

这解决了问题(请参阅@gct 的回答以了解原因):

static PyObject *Hi_overload_switch(PyBox *self,  PyObject *args)

PyObject *x = Py_None;
PyObject *y = Py_None;

if (!PyArg_ParseTuple(args, "|OO", &x, &y))
    return NULL;

if (PyUnicode_Check(x) && PyLong_Check(y) && y != Py_None)

    printf("A!\n\n");

    char* s = PyBytes_AsString(PyUnicode_AsUTF8String(x));

    Py_DECREF(x);

    return pyBox_sayHi_char_int(self, s, PyLong_AsLong(y));


else if (PyUnicode_Check(x) && y == Py_None)
   
    printf("B!\n\n");

    char* s = PyBytes_AsString(PyUnicode_AsUTF8String(x)); 

    Py_DECREF(x);

    return pyBox_sayHi_char(self, s);

else

    Py_RETURN_NOTIMPLEMENTED;

Py_RETURN_NOTIMPLEMENTED;

【讨论】:

以上是关于Python C++ API - 具有可变数量参数的重载函数的主要内容,如果未能解决你的问题,请参考以下文章

为具有可变数量参数的不同函数编写通用包装器

Python 3 类型,具有任意数量的包含类型的自定义可变参数泛型,如何?

具有不同数量参数的函数中的 C++ 代码重复

Python 用可变数量的位置参数和可选参数装饰方法

如何声明具有可变数量元素的数组[C++]?

可以将可变数量的参数传递给函数吗?