PyArg_ParseTupleAndKeywords是如何工作的?

24

我一直在尝试学习如何编写Python的C扩展,并希望确保我理解PyArg_ParseTupleAndKeywords的工作方式。

我认为第一个参数是指向以它们被传递的顺序排列的C扩展函数中传递的参数数组的PyObject指针。第二个参数是传递的关键字列表,它们被传递的位置以及很可能是某种指示标志,告诉关键字开始的位置和位置变得无关紧要。

然后,PyArg_ParseTupleAndKeywords使用其关键字列表(第四个参数)将使用关键字指定的参数与格式字符串(第三个参数)以及C变量的地址(第五个及更多参数)进行映射,以便应将哪些值复制到相应的变量地址中。

我的理解正确吗?当我阅读在线文档时,我只看到“位置参数和关键字参数”的参考,这让我感到有点不知所措。处理PyArg_ParseTupleAndKeywords的Python解释器文件在哪里?

2个回答

22

在 Python 中模拟以下内容:

def keywords(a, b, foo=None, bar=None, baz=None):
    pass

以下方法可行:
static PyObject *keywords(PyObject *self, PyObject *args, PyObject *kwargs)
{
    char *a;
    char *b;
    char *foo = NULL;
    char *bar = NULL;
    char *baz = NULL;

    // Note how "a" and "b" are included in this
    // even though they aren't supposed to be in kwargs like in python
    static char *kwlist[] = {"a", "b", "foo", "bar", "baz", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|sss", kwlist, 
                                     &a, &b, &foo, &bar, &baz)) 
    {
        return NULL;
    }

    printf("a is %s\n", a);
    printf("b is %s\n", b);
    printf("foo is %s\n", foo);
    printf("bar is %s\n", bar);
    printf("baz is %s\n", baz);

    Py_RETURN_NONE;
}

// ...

static PyMethodDef SpamMethods[] = 
{
    // ...
    {"keywords", (PyCFunction) keywords, METH_VARARGS | METH_KEYWORDS, "practice kwargs"},
    {NULL, NULL, 0, NULL}
    // ...
}

并且要使用它:

from spam import keywords

keywords()         # Fails, require a and b
keywords('a')      # fails, requires b
keywords('a', 'b')
keywords('a', 'b', foo='foo', bar='bar', baz='baz') 
keywords('a', 'b','foo', 'bar', 'baz')
keywords(a='a', b='b', foo='foo', bar='bar', baz='baz')

奇怪——我不能编辑。当您转换“keywords”函数时,您想将其转换为PyCFunctionWithKeywords,而不是PyCFunction - Jim Pivarski
1
@JimPivarski 看起来应该是 PyCFunction https://dev59.com/-WLVa4cB1Zd3GeqP1flq - Aaron Zorel
4
setup.py中设置language = "c++"并使用-std=c++11进行构建时,针对行static char *kwlist[] = {"", "", NULL};会发出此警告warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]。请注意,警告的意思是不允许将字符串常量转换为“char *”。 - user
C++在const方面有一些不同的规则。在这种情况下,应该使用const char *kwlist[]而不是static char *kwlist - the paul
@user,请尝试使用const_cast<char **>(kwlist) - Alexander Lubyagin
@user,请尝试使用 const_cast<char **>(kwlist), - Alexander Lubyagin

8
你是否阅读过位于http://docs.python.org/c-api/arg.html的开头解释?它做了一个很好的工作来解释正在发生的事情。不要直接去查找PyArg_ParseTupleAndKeywords的具体参考; 它假定你已经阅读了上面的文本,并且本身并不是很有帮助。
虽然你几乎做到了,但第一个参数确实是传入位置参数的列表。第二个是传入关键字参数的映射(将给定的关键字名称映射到给定的值)。第四个参数实际上是您的函数准备接受的关键字列表。是的,第三个参数是格式字符串,第五个及以后是C指针,用于复制值。
你会在Python/getargs.c下找到PyArg_ParseTupleAndKeywords()

2
除了 C API 文档之外,http://docs.python.org/2/extending/extending.html 上还有一个易读的摘要。 - timbo
http://docs.python.org/c-api/arg.html 的文档相当糟糕。 - smbear

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