接受可选整数的Python C扩展函数

接受可选整数的Python C扩展函数,python,c,python-c-api,Python,C,Python C Api,我想在C扩展模块中实现以下Python函数: def value(x: Optional[int] = None) -> Optional[int]: if x is None: # act like a getter return APIGetValue() # retrieve the value from an external library # act like a setter APISetValue(x) # pas

我想在C扩展模块中实现以下Python函数:

def value(x: Optional[int] = None) -> Optional[int]:
    if x is None:
        # act like a getter
        return APIGetValue()  # retrieve the value from an external library
    # act like a setter
    APISetValue(x)  # pass the value to an external library
    return None
以下是我到目前为止得到的信息:

static PyObject* MyLib_PyValue(PyObject *self, PyObject *args, PyObject *kwargs) {
    static char *kwlist[] = { "x", NULL };
    int x;
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:value", kwlist, &x)) {
        return NULL;
    }
    if (x == NULL) {
        return PyLong_FromLong(APIGetValue());
    }
    APISetValue(x);
    Py_RETURN_NONE;
}

使用args调用函数是可行的,但是当作为getter调用
value()
时,我得到的是
1
,而不是
NULL
。我应该如何进行?我还不太熟悉Python的C API。

首先,不能有NULL int。NULL是指针的东西。由于C类型转换的工作方式以及
NULL
宏的定义方式,
x==NULL
和int
x
通常执行以下两种操作之一:其行为类似于
x==0
,或者产生编译时错误

二是引用,

与可选参数对应的C变量应初始化为其默认值-当未指定可选参数时,PyArg_ParseTuple()不会触及相应C变量的内容

这同样适用于
PyArg_ParseTupleAndKeywords
。您的
x
未初始化,并且
PyArg_ParseTupleAndKeywords
没有为其写入值,因此在
x==NULL
比较中访问
x
的值是未定义的行为


您需要初始化
x
,并且需要使用一种类型,该类型实际上允许您检测缺少的值。这可能意味着将
x
声明为
PyObject*x=NULL
并将
“|O:value”
传递给
PyArg_ParseTupleAndKeywords
,然后在函数中处理到C long的转换,而不是依赖
PyArg_ParseTupleAndKeywords
来完成。这是最终结果,以防有人需要一个工作片段:

static PyObject* MyLib_PyValue(PyObject *self, PyObject *args, PyObject *kwargs) {
    static char *kwlist[] = { "x", NULL };
    PyObject *pyX = NULL;
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:value", kwlist, &pyX)) {
        return NULL;
    }
    if (pyX == NULL) { // getter
        return PyLong_FromLong(APIGetValue());
    }
    // setter
    int x = (int)PyLong_AsLong(pyX);
    if (PyErr_Occurred()) {
        return NULL;
    }
    if (x < 0) {
        PyErr_SetString(PyExc_ValueError, "x must be positive");
        return NULL;
    }
    APISetValue(x);
    Py_RETURN_NONE;
}
static PyObject*MyLib\u PyValue(PyObject*self、PyObject*args、PyObject*kwargs){
静态字符*kwlist[]={“x”,NULL};
PyObject*pyX=NULL;
if(!PyArg_ParseTupleAndKeywords(args、kwargs、“|O:value”、kwlist和pyX)){
返回NULL;
}
如果(pyX==NULL){//getter
从long(APIGetValue())返回PyLong_;
}
//塞特
int x=(int)pyX;
如果(Pyrr_发生()){
返回NULL;
}
if(x<0){
PyErr_SetString(PyExc_ValueError,“x必须为正”);
返回NULL;
}
APISetValue(x);
Py_返回_无;
}

太棒了,谢谢你的快速回答!在C和Python C API中完成我的第一步,请容忍愚蠢的问题。