Python PyArg_ParseTupleAndKeywords()中的无值PyObject为NULL
我正在将一个扩展类型对象传递给Python函数,该函数需要将这种类型的变量传递给C函数。我的扩展类型如下所示:Python PyArg_ParseTupleAndKeywords()中的无值PyObject为NULL,python,c,python-c-api,python-extensions,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; typedef struct rec_rset_s *rec_rset_t; if(rset->rst == 0x89e8a0) rset->rst = NULL;
typedef struct {
PyObject_HEAD
rec_rset_t rst; //need to pass this to C function
} RSet;
typedef struct rec_rset_s *rec_rset_t;
if(rset->rst == 0x89e8a0)
rset->rst = NULL;
rec_rset_t是指向结构的指针,如下所示:
typedef struct {
PyObject_HEAD
rec_rset_t rst; //need to pass this to C function
} RSet;
typedef struct rec_rset_s *rec_rset_t;
if(rset->rst == 0x89e8a0)
rset->rst = NULL;
其中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);
}
问题是我希望能够为RSet
对象传递None
,并使其在C中转换为NULL,以及使变量rst
为NULL。如果我传递None
,我会得到一个分段错误,因为PyArg\u ParseTupleAndKeywords
的“O”
选项不处理PyObject
的任何值(这与“s”
选项不同,在传递NULL
字符串时,我们可以使用“z”
)。我尝试手动检查Py_None
对象,但没有成功。所以现在我在做一些不太优雅的事情,比如:
typedef struct {
PyObject_HEAD
rec_rset_t rst; //need to pass this to C function
} RSet;
typedef struct rec_rset_s *rec_rset_t;
if(rset->rst == 0x89e8a0)
rset->rst = NULL;
因为当我传递None
时,这就是rset->rst
的值,然后将这个rset->rst
传递给cquery
函数。
当接收扩展类型对象时,如何将None
值传递给PyArg\u ParseTuple
?有没有一个通用的方法来实现这一点
编辑:
我错误地检查了Py_None的rset->rst值。检查
if((PyObject *)rset == Py_None)
计算结果为true,因此是,不处理任何值。但是值rset->rst(我传递给cquery)不是NULL,这是我想要的。手动设置rset->rst=NULL是唯一的方法吗 问题在于,如果将rset设置为Py_None(PyObject*),则仅保证PyObject_头定义的字段有效;基本上,你得到了一个指向非资源集的指针 您不应该将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!,它为您进行类型验证,但我似乎记得这不允许进行任何类型验证,在本例中,您希望这样。)“因为PyArg_ParseTupleAndKeywords的“O”选项不处理PyObject“”的任何值?”???如果它确实处理
None
@Bakuriu是正确的,'O'允许None@Bakuriu谢谢,我检查得太匆忙了。请参见问题编辑。