如何只解析' kwargs'并在调用PyArg_ParseTupleAndKeywords时跳过args?

时间:2014-12-15 13:42:25

标签: python python-c-api

我正在调用一个函数,它接受一个位置参数列表,后跟关键字参数。我想分别处理args和kwargs。不幸的是,与位置参数的PyArg_ParseTuple不同,关键字参数没有等效的PyArg_ParseKeywords。我试图通过传递Py_None(也是NULL)来代替args来阻止解析位置参数:

static PyObject* test_func(PyObject* self, PyObject* args, PyObject *kwargs)
{
    static const char *kwList[] = {"kw1", "kw2", NULL};
    const char* kw1_val = NULL;
    PyObject* kw2_val = NULL;

    if (! PyArg_ParseTupleAndKeywords(Py_None, 
                                      kwargs,
                                      "zO",
                                      const_cast<char**>(kwList),
                                      &kw1_val,
                                      &kw2_val))
    {
        return NULL;
    }
}

有Py_None(或NULL)导致:

Python/getargs.c:1390: bad argument to internal function

如果我用args替换Py_None,我会收到以下错误:

TypeError: function takes at most 2 arguments (4 given)

上面发生TypeError,因为它解包了2个位置args和2个传递给test_func的关键字args,而只有两个变量kw1_val和kw2_val在解析方法中接收这4个值。

有没有办法处理上述情况?请注意,位置参数可以包含任意数量的值。

3 个答案:

答案 0 :(得分:2)

尝试传递空元组而不是Py_None

static PyObject* test_func(PyObject* self, PyObject* args, PyObject *kwargs)
{
    static const char *kwList[] = {"kw1", "kw2", NULL};
    const char* kw1_val = NULL;
    PyObject* kw2_val = NULL;

    PyObject *retvalue = NULL;
    PyObject *empty = PyTuple_New(0);

    if (empty == NULL){
        goto out;
    }

    if (! PyArg_ParseTupleAndKeywords(empty, 
                                      kwargs,
                                      "zO",
                                      const_cast<char**>(kwList),
                                      &kw1_val,
                                      &kw2_val))
    {
        goto out;
    }

    // other code here

out:
    Py_XDECREF(empty);
    return retvalue;
}

答案 1 :(得分:0)

我认为您在这里遇到了经典的X-Y问题。不用担心,我有相同的人。

这里的Y是PyArg_ParseTupleAndKeywords,而实际上X只是“在Python C API中仅解析kwargs”。

kwargs只是一个Python dict(),因此,如果我们真的不在乎位置参数,则可以使用现有的C API函数来处理dict()PyDict_* family of functions

因此,如果我们有PyCFunction个原型:

PyObject* Amit(PyObject *self, PyObject *args, PyObject *keywds);

我们知道keywds在Python 2和Python 3中都是PyDict。因此我们可以例如这个:

PyObject* layerp = NULL;
if (keywds != NULL) layerp = PyDict_GetItemString(keywds, "layer");

PyDict_GetItemString将返回NULL而不会设置错误,因此我们只需检查layerp中的NULL即可知道是否有可选的关键字参数。

答案 2 :(得分:-1)

c++ 按键排序

p::list l;

l.sort(*tuple(), **dict(make_tuple(make_tuple("key", *[](object const& x){ return x["y"];}))));