Как работает PyArg_ParseTupleAndKeywords?
Я пытался научиться писать C-расширения для Python и хочу быть уверенным, что я понимаю, как работает PyArg_ParseTupleAndKeywords.
Я считаю, что первым аргументом является указатель PyObject, который указывает на массив аргументов, передаваемых в функцию C-расширения в том порядке, в котором они были переданы. Второй аргумент - это список переданных ключевых слов, позиции, на которых они были переданы, и, скорее всего, какой-то индикаторный флаг, указывающий, в какой позиции ключевые слова начинаются и позиция становится неактуальной.
PyArg_ParseTupleAndKeywords затем использует свой список ключевых слов (4-й аргумент) для сопоставления между аргументами, указанными с ключевым словом, и как строку формата (третий аргумент), так и адреса переменных C (аргументы 5 и +), которым должны быть скопированы соответствующие значения.
Правильно ли я понимаю? Когда я читаю онлайн-документацию, все, что я вижу, это ссылки на "позиционные аргументы и аргументы ключевых слов", которые оставляют меня немного в темноте. Где находится файл для интерпретатора Python, который обрабатывает PyArg_ParseTupleAndKeywords?
Ответы
Ответ 1
Вы прочитали объяснение открытия в http://docs.python.org/c-api/arg.html? Это довольно хорошая работа, объясняя, что происходит. Не обращайтесь к конкретной ссылке для PyArg_ParseTupleAndKeywords
; он предполагает, что вы прочитали текст выше и не очень полезны сами по себе.
Тем не менее, вы его почти получили. Первый аргумент - действительно список входящих позиционных аргументов. Вторая - это карта входящих аргументов ключевого слова (сопоставление заданного ключевого слова с заданным значением). Четвертый аргумент - это фактически список ключевых слов, которые ваша функция готова принять. Да, третий аргумент - это строка формата, а пятый и более поздние - это C-указатели, в которые скопированы значения.
Вы найдете PyArg_ParseTupleAndKeywords()
под Python/getargs.c
.
Ответ 2
Чтобы подражать следующему в 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')