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

3

我正在调用一个函数,它接受一个位置参数列表和关键字参数。我想要分别处理args和kwargs。不幸的是,与PyArg_ParseTuple对于位置参数不同,没有相应的PyArg_ParseKeywords可以用于关键字参数。我尝试通过在args的位置上传递Py_None(也可以是NULL)来防止解析位置参数:

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 错误是由于在解析方法中,我传递给 test_func 的 2 个位置参数和 2 个关键字参数被拆分开来,而只有 kw1_val 和 kw2_val 这两个变量可以接收这 4 个值。
有没有一种处理上述情况的方法?请注意,位置参数可以有任意数量的值。
3个回答

3
尝试传递一个空元组而不是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;
}

谢谢Kevin,这个可行。但是我仍然想知道为什么我们只需要处理关键词的解决方法。 - Amit
2
在Python 3中,您可以通过用"|$"前缀格式字符串来使参数成为关键字参数。但这也会使它们变成可选的;您似乎想要强制使用必须的关键字参数,目前还不支持该功能。 - Kevin

1
我认为你遇到了一个典型的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是一个PyDict,在Python 2和Python 3中都是如此。所以我们可以这样做:
PyObject* layerp = NULL;
if (keywds != NULL) layerp = PyDict_GetItemString(keywds, "layer");

PyDict_GetItemString会在不设置错误的情况下返回NULL,因此我们只需检查layerp是否为NULL,就可以知道我们是否得到了一个可选的关键字参数。


-1

c++ 按键排序

p::list l;

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


这与问题有什么关系呢? - DavidW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接