Каков «правильный» способ передачи логического значения в расширение Python C? - PullRequest
23 голосов
/ 16 февраля 2012

Это простой пример из документации по питону (http://docs.python.org/extending/extending.html):

static PyObject *
spam_system(PyObject *self, PyObject *args)
{
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = system(command);
    return Py_BuildValue("i", sts);
}

Если я хочу передать дополнительный логический параметр в функцию - каков «правильный» способ сделать это?

Кажется, нет опции bool для передачи в PyArg_ParseTuple (). Поэтому я подумал о следующем:

  1. читать целое число и просто использовать значение (так как bool является подклассом int)
  2. вызовите PyBool_FromLong () для целого числа
  3. для чтения и объекта и вызовите PyBool_Check () для проверки, что это bool
  4. , возможно, есть способ получить любой тип переменнойи получить его значение истинности (т. е. пустой массив будет ложным и т. д.), что обычно делает функция python.

Любой из этих предпочтительных? Другие варианты?

Ответы [ 3 ]

21 голосов
/ 16 февраля 2012

4, может быть, есть способ получить любой тип переменной и получить ее значение истинности (т. Е. Пустой массив будет ложным и т. Д.), Что обычно и делает функция python.Да: (из Справочник по Python / C API )

int PyObject_IsTrue(PyObject *o)

Возвращает 1, если объект o считается истинным, и 0 в противном случае.Это эквивалентно выражению Python not not o.В случае ошибки верните -1. ​​

РЕДАКТИРОВАТЬ.Чтобы ответить на реальный вопрос, я думаю, что подход 1 является правильным, потому что int действительно является соответствующим типом в C. Подход 4 хорош, но если вы документируете свою функцию как принятие bool, вы не обязаны принимать только любой объект.Явные проверки типов, как в 3 без причины, осуждаются в Python.Преобразование в другой объект Python, как в 2, не помогает вашему C-коду.

15 голосов
/ 22 мая 2012

В настоящее время синтаксический анализ целого числа (как "i") является приемлемым способом получения bool.

Начиная с Python 3.3, PyArg_ParseTuple будет принимать "p" (для «предиката»), для последние НОВОСТИ :

  • Выпуск # 14705 : семейство функций PyArg_Parse () теперь поддерживает модуль формата 'p', который принимаетаргумент "логический предикат".Он преобразует любое значение Python в целое число - 0, если оно равно «false», и 1 в противном случае.

Обратите внимание, что при использовании PyArg_ParseTuple с "p" аргумент должен быть(указатель на) int, а не тип C99 bool:

int x;    // not "bool x"
PyArg_ParseTuple(args, kwds, "p", &x);
6 голосов
/ 16 сентября 2013

Я нашел другой подход:

PyObject* py_expectArgs;
bool expectArgs;

PyArg_ParseTupleAndKeywords(args, keywds, (char *)"O!", (char **)kwlist, &PyBool_Type, &py_expectArgs);

expectArgs = PyObject_IsTrue(py_expectArgs);

В случае неправильного вызова параметра есть «автоматическое» исключение »аргумент 1 должен быть bool, а не int"

...