PyArg_ParseTupleAndKeywords()中没有将PyObject值赋值为NULL

时间:2013-09-02 10:17:11

标签: python c python-c-api python-extensions

我将扩展类型对象传递给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"的{​​{1}}选项无法处理PyArg_ParseTupleAndKeywords的无值(这与PyObject不同选项,如果我们传递"s"字符串,我们可以使用"z"。我尝试手动检查NULL对象,但它没有用。所以目前我正在做一些不太优雅的事情,比如:

Py_None

因为当我通过if(rset->rst == 0x89e8a0) rset->rst = NULL; ,然后将此rset->rst传递给None函数时,这是rset->rst的值。 在接收扩展类型对象时,如何将cquery值传递给None?有没有一般的方式来完成这个?

编辑:

我错误地检查了rset-> rst对Py_None的值。检查

PyArg_ParseTuple

评估为true,所以是的,没有处理。但是值rset-> rst(我传递给cquery)不是NULL,这就是我想要的。手动设置rset-> rst = NULL是唯一的方法吗?

1 个答案:

答案 0 :(得分:2)

问题是如果rset设置为Py_None(PyObject *),则只保证PyObject_HEAD定义的字段有效;基本上你已经找回了一个不是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!,它为你进行类型验证,但我似乎记得在这种情况下不允许使用None。)