【问题标题】:None value PyObject to NULL in PyArg_ParseTupleAndKeywords()PyArg_ParseTupleAndKeywords() 中的 None 值 PyObject 为 NULL
【发布时间】:2013-09-05 10:02:10
【问题描述】:

我正在将扩展类型对象传递给 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);
}

问题是我希望能够为RSet 对象传递None,并让它在C 中转换为NULL,并且让变量rst 为NULL。如果我通过None,我会遇到分段错误,因为PyArg_ParseTupleAndKeywords"O" 选项不处理PyObject 的None 值(这与"s" 选项不同,我们可以使用"z" 如果我们正在传递一个NULL 字符串)。我尝试手动检查 Py_None 对象,但没有成功。所以目前我正在做一些不太优雅的事情,像这样:

if(rset->rst == 0x89e8a0)
    rset->rst = NULL;

因为当我传递None,然后将这个rset->rst 传递给cquery 函数时,那是rset->rst 的值。 接收扩展类型对象时如何将None 值传递给PyArg_ParseTuple?有没有一种通用的方法可以做到这一点?

编辑:

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

if((PyObject *)rset == Py_None)

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

【问题讨论】:

  • "因为 PyArg_ParseTupleAndKeywords 的 "O" 选项不处理 PyObject 的 None 值 " ??? AFAIK它确实处理None
  • @Bakuriu 是正确的,'O' 确实允许 None
  • @Bakuriu 谢谢,我的检查太仓促了。请参阅问题编辑。

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


【解决方案1】:

问题是如果rset设置为Py_None(一个PyObject*),只有PyObject_HEAD定义的字段保证有效;本质上,你已经得到了一个指向不是 RSet 的东西的指针。

您应该修改代码,使其最初引用 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,在这种情况下你想要它。)

【讨论】:

    猜你喜欢
    • 2023-03-02
    • 2022-01-22
    • 2012-08-11
    • 1970-01-01
    • 1970-01-01
    • 2017-03-07
    • 2020-11-08
    • 2012-04-14
    • 1970-01-01
    相关资源
    最近更新 更多