True *args and **kwargs in Python C extension

狂风中的少年 提交于 2020-12-05 12:15:28

问题


I am developing Python 3 C extension.

Can I get the equivalent or arbitrary positional or keyword arguments?

For instance, in Python, I can write:

def fun(name, parent, *args, **kwargs):
    # do something with name and parent
    # do something with args and kwargs
    pass

But I cannot find of a simple equivalent in C. While we can perfectly write functions with PyObject* args and PyObject* kwargs, I cannot easily "parse out" name and parent from whichever (args/kwargs) it came.

Take:

static PyObject* myFunction(PyObject* self, PyObject* args, PyObject* kwargs) {
    char* kwds[] = {"parent", "name", NULL};
    PyObject* name = NULL;
    PyObject* parent = NULL;
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwds, &parent, &name)) {
        goto errorParseTupleAndKeywords;
    }
    /* Do something with name and parent */
    /* parent and name maybe have appeared either in args or kwargs */
    /* But I don't have any extra positional (*args) or keyword (**kwargs) here */    
}

A "manual" approach that I could think of looks roughly like:

static PyObject* myFunction(PyObject* self, PyObject* args, PyObject* kwargs) {
    PyObject* name = NULL;
    PyObject* parent = NULL;
    int inKwargs = 0;
    // Pretend to do something with parent
    if (PyDict_GetItemString(kwargs, "parent")) {
        inKwargs++;
        PyDict_DelItemString(kwargs, "parent");
    }
    // Pretend to do something with name
    if (PyDict_GetItemString(kwargs, "name")) {
        inKwargs++;
        PyDict_DelItemString(kwargs, "name");
    }
    // Not sure if -1 works here
    PyObject* newArgs = PyTuple_GetSlice(args, inKwargs, -1); // this is *args
    // the remaining kwargs can be used as **kwargs
}

回答1:


In the C API, PyObject* args really is a Python tuple, and PyObject* kwargs really is a Python dictionary. At least that is what PyArg_ParseTupleAndKeywords internally requires:

int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, char **kwlist, ...)
{
    // …
    if ((args == NULL || !PyTuple_Check(args)) ||
        (keywords != NULL && !PyDict_Check(keywords)) ||
        format == NULL ||
        kwlist == NULL)
    {
        PyErr_BadInternalCall();
        return 0;
    }

    // …
}

The actual implementation of that function in vgetargskeywords also asserts this again, so you should be fine with replacing your PyArg_ParseTupleAndKeywords call with manual extraction from the objects.

This means that you can use both the tuple and dict APIs, or use the iterator protocol to iterate over the items in these objects.



来源:https://stackoverflow.com/questions/35820661/true-args-and-kwargs-in-python-c-extension

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!