Python C API: включить тип PyObject - PullRequest
7 голосов
/ 22 июня 2010

У меня есть некоторый код для взаимодействия Python с C ++, который работает нормально, но каждый раз, когда я смотрю на него, я думаю, что должен быть лучший способ сделать это.На стороне C ++ есть «вариантный» тип, который может работать с фиксированным диапазоном базовых типов - int, real, string, vector вариантов и т. Д. У меня есть некоторый код, использующий Python API для преобразования из эквивалентных типов Python.Это выглядит примерно так:

variant makeVariant(PyObject* value)
{  
  if (PyString_Check(value)) {
    return PyString_AsString(value);
  }
  else if (value == Py_None) {
    return variant();
  }
  else if (PyBool_Check(value)) {
    return value == Py_True;
  }
  else if (PyInt_Check(value)) {
    return PyInt_AsLong(value);
  }
  else if (PyFloat_Check(value)) {
    return PyFloat_AsDouble(value);
  }
  // ... etc

Проблема заключается в цепочке if-else ifs.Похоже, что он вызывает оператор switch или таблицу или карту функций создания, которые обозначены идентификатором типа.Другими словами, я хочу иметь возможность написать что-то вроде:

  return createFunMap[typeID(value)](value);

Исходя из анализа документации по API, было неочевидно, как лучше всего получить здесь «typeID» напрямую.Я вижу, что могу сделать что-то вроде этого:

  PyTypeObject* type = value->ob_type;

По-видимому, это быстро приводит меня к информации о типах, но какой самый чистый способ использовать ее для связи с ограниченным набором типов, которые меня интересуют?1010 *

1 Ответ

3 голосов
/ 22 июня 2010

В некотором смысле, я думаю, что вы ответили на свой вопрос.

Где-то вам придется выбирать функциональность на основе данных. Способ сделать это в C - использовать указатели на функции.

Создайте карту object_type-> сопоставителей функций ... где каждая функция имеет четко определенный интерфейс.

variant PyBoolToVariant(PyObject *value) {
    return value == Py_True;
}

Map<PyTypeObject*,variant* (PyObject*)> function_map;

function_map.add(PyBool, PyBoolToVariant);

Теперь ваш makeVariant может выглядеть следующим образом.

variant makeVariant(PyObject *value) {
    return (*function_map.get(value->ob_type))(value);
}

Сложная часть - получить правильный синтаксис для объекта Map. Кроме того, я предполагаю, что есть объект Map, который вы можете использовать, который принимает параметры типа (<PyTypeObject*, variant*(PyObject*)).

Возможно, я не совсем правильно понял синтаксис для второго типа Карты. Это должен быть указатель на функцию, которая берет один указатель и возвращает указатель на вариант.

Надеюсь, это полезно.

...