将布尔值传递给Python C扩展的"正确"方法是什么?

shy*_*gon 23 python python-c-api python-c-extension

这是python文档(http://docs.python.org/extending/extending.html)中的一个简单示例:

static PyObject *
spam_system(PyObject *self, PyObject *args)
{
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = system(command);
    return Py_BuildValue("i", sts);
}
Run Code Online (Sandbox Code Playgroud)

如果我想将另一个布尔参数传递给函数 - 这是什么"正确"的方法呢?

似乎没有传递给PyArg_ParseTuple()的bool选项.所以我想到了以下几点:

  1. 读取一个整数并只使用该值(因为bool是int的子类)
  2. 在整数上调用PyBool_FromLong()
  3. 读取和对象并调用PyBool_Check()来验证它是一个bool
  4. 也许有一种方法可以获得任何类型的变量并获得其真值(即空数组将是假数据等),这是python函数通常所做的.

这些中哪一个更好?其他选择?

Jan*_*ila 21

4也许有一种方法可以获得任何类型的变量并获得其真值(即空数组将是假数据等),这正是python函数通常所做的.

是的:(来自Python/C API参考)

int PyObject_IsTrue(PyObject *o)
Run Code Online (Sandbox Code Playgroud)

如果对象o被认为是真,则返回1,否则返回0.这相当于Python表达式而不是o.失败时,返回-1.

编辑.为了回答实际问题,我认为方法1是正确的,因为int实际上是C中的相应类型.方法4很好,但如果你将你的函数记录为bool,你没有义务接受任何对象.在Python中,没有理由的显式类型检查在3中是不受欢迎的.像2中一样转换为另一个Python对象对您的C代码没有帮助.


eca*_*mur 16

目前,解析整数(as "i")是获取bool的可接受方式.

根据Python 3.3,PyArg_ParseTuple将接受"p"(对于"谓词"),根据最新消息:

  • 问题#14705:PyArg_Parse()系列函数现在支持'p'格式单元,它接受"布尔谓词"参数.它将任何Python值转换为整数 - 如果为"false"则为0,否则为1.

请注意,使用PyArg_ParseTuplewith时"p",参数必须是(指向)int,而不是C99 bool类型:

int x;    // not "bool x"
PyArg_ParseTuple(args, kwds, "p", &x);
Run Code Online (Sandbox Code Playgroud)

  • 我一直在使用它,发现在CI中必须将变量声明为`int`(不是`bool`).或者,当使用多个bool时,它们将无法正确设置(可能是`bool`和`int`之间大小差异的问题). (2认同)

oko*_*ian 6

我找到了另一种方法:

PyObject* py_expectArgs;
bool expectArgs;

PyArg_ParseTupleAndKeywords(args, keywds, (char *)"O!", (char **)kwlist, &PyBool_Type, &py_expectArgs);

expectArgs = PyObject_IsTrue(py_expectArgs);
Run Code Online (Sandbox Code Playgroud)

如果错误的参数调用有"自动"异常"参数1必须是bool,而不是int"