Как правильно передать логическое значение расширению Python C?

Это простой пример из документации по Python (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(), чтобы убедиться, что это логическое значение
  4. возможно, есть способ получить переменную любого типа и получить ее истинное значение (т. е. пустой массив будет ложным и т. д.), что обычно делает функция python.

Что-то из этого предпочтительнее? Другие опции?


person shygon    schedule 16.02.2012    source источник


Ответы (3)


4, возможно, есть способ получить переменную любого типа и получить ее истинное значение (т.е. пустой массив будет ложным и т. д.), что обычно делает функция python.

Да: (из Справочника Python/C API)

int PyObject_IsTrue(PyObject *o)

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

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

person Janne Karila    schedule 16.02.2012

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

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

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

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

int x;    // not "bool x"
PyArg_ParseTuple(args, kwds, "p", &x);
person ecatmur    schedule 22.05.2012
comment
Я использовал это и обнаружил, что в C я должен объявлять переменные как int (а не bool). Или, при использовании нескольких логических значений, они не будут установлены правильно (возможно, проблема с разницей в размерах между bool и int). - person szmoore; 05.02.2015
comment
@szmoore Здесь указано, что здесь используется целое число в ответе. - person kevr; 06.10.2017
comment
Да, но часто в C вы можете использовать int и bool взаимозаменяемо, в этом случае вы не можете. Могу удалить свой комментарий, если он лишний. - person szmoore; 09.10.2017
comment
@szmoore извините, я пропустил ваш оригинальный комментарий. Это важный момент, и я обновил свой ответ. Спасибо! - person ecatmur; 09.10.2017

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

PyObject* py_expectArgs;
bool expectArgs;

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

expectArgs = PyObject_IsTrue(py_expectArgs);

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

person okocian    schedule 16.09.2013