我正在将扩展类型对象传递给Python函数,该函数需要将此类型中的变量传递给C函数我的扩展类型如下:

typedef struct {
    PyObject_HEAD
    rec_rset_t rst;  //need to pass this to C function
} RSet;

rec_rset_t是指向结构的指针,如下所示:
typedef struct rec_rset_s *rec_rset_t;

其中,rec_rset_s的定义如下:
struct rec_rset_s
{
  size_t size;
  int a,b;
}

所以我有一个Python扩展函数,它接收一个RSet对象作为参数。
static PyObject*
Recon_query(Recon *self, PyObject *args, PyObject *kwds)
{
    const char  *type;
    RSet        *tmp = PyObject_NEW(RSet, &RSetType);
    rec_rset_t  res;
    static char *kwlist[] = {"type", "rset", NULL};
    if (! PyArg_ParseTupleAndKeywords(args, kwds, "zO", kwlist,
                                      &type, &rset))
      {
        return NULL;
      }
    res = cquery(self->rcn, type, rset->rst);
    tmp->rst = res;
    return Py_BuildValue("O",tmp);
}

问题是,我希望能够为None对象传递RSet,并使它在C中转换为NULL,同时使变量rst为NULL如果我通过None,我会得到一个分段错误,因为"O"PyArg_ParseTupleAndKeywords选项不处理PyObject的任何值(这与"s"选项不同,在这里,如果我们传递"z"字符串,我们可以使用NULL)我试图手动检查Py_None对象,但没有成功所以目前我在做一些不太优雅的事情,比如:
if(rset->rst == 0x89e8a0)
    rset->rst = NULL;

因为这是当我通过rset->rstNone的值,然后把这个rset->rst传递给cquery函数。
如何在接收扩展类型对象时将None值传递给PyArg_ParseTuple有没有一般的方法来做这件事?
编辑:
我错误地检查了rset->rst的值检查
if((PyObject *)rset == Py_None)

计算结果为true,因此是,不处理任何但是值rset->rst(我传递给cquery)不为空,这是我想要的手动设置rset->rst=NULL是唯一的方法吗?

最佳答案

问题是,如果rset设置为Py_None(PyObject*),则只有PyObject_头定义的字段才保证有效;实际上,您已经返回了指向非rset的某个字段的指针。
与其将rset->rst设置为NULL(如果rset==Py_None,则可能是修改了不应该修改的内存),不如修改代码,使其最初引用PyObject*,然后仅在确定不是Py_None时强制转换到rset*:

PyObject *rsetobj = NULL;
rec_rset_t rst;
if (! PyArg_ParseTupleAndKeywords(args, kwds, "zO", kwlist,
                                      &type, &rsetobj))
      {
        return NULL;
      }
if (rsetobj == Py_None)
    rst = NULL;
else
    rst = ((RSet*)rsetobj)->rst;
res = cquery(self->rcn, type, rst);

您可能还希望在强制转换为RSet之前显式检查对象类型(或者使用O!,它为您进行类型验证,但我似乎还记得,在本例中不允许任何类型验证

关于python - 在PyArg_ParseTupleAndKeywords()中,没有将PyObject的值设置为NULL,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18570769/

10-10 14:05