Swig Typemap для Python: массивы ввода и вывода - PullRequest
4 голосов
/ 07 сентября 2010

У меня есть функция C, которую я хочу использовать в Python:

extern int convertAtoB( stateStruct *myStruct,
                        const double PointA[3],
                        double PointB[3]);

Используя SWIG, я думаю, что мне нужно определить карту типов для преобразования двух точек (PointA - вход, PointB - выход), поэтомутот Питон может использовать это.Кажется, в typemaps.i нет карты типов, которая бы работала с этим, поэтому я должен определить ее.Я не могу найти примеры этого для массивов в документации SWIG.

Я хотел бы использовать эту библиотеку следующим образом:

s = externalStruct()
point_a = [1, 2, 3]
result, point_b = convertAtoB(s, point_a)
print point_b
"expect [4, 5, 6]"

Как бы я это сделал?Спасибо

Ответы [ 3 ]

3 голосов
/ 30 мая 2011

Ты почти у цели.Чтобы избавиться от фиктивного аргумента в сигнатуре питона, вам нужно изменить %typemap(in) для PointB[3] на %typemap(in,numinputs=0), чтобы дать команду SWIG игнорировать это входное значение (вы все равно уже его копию).Это удалит фиктивный аргумент из сигнатуры метода python.

Я не уверен, однако, если вам нужно скопировать весь %typemap(in) для этой специализации.Вероятно, есть способ повторно использовать фактическую карту типов, но я не знаю как.В противном случае вы получите дополнительно

%typemap(in,numinputs=0) double PointB[3] (double temp[$1_dim0]) {
  int i;
  if (!PySequence_Check($input)) {
    PyErr_SetString(PyExc_ValueError,"Expected a sequence");
    return NULL;
  }
  if (PySequence_Length($input) != $1_dim0) {
    PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements");
    return NULL;
  }
  for (i = 0; i < $1_dim0; i++) {
    PyObject *o = PySequence_GetItem($input,i);
    if (PyNumber_Check(o)) {
      temp[i] = (double) PyFloat_AsDouble(o);
    } else {
      PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");      
      return NULL;
    }
  }
  $1 = temp;
}
1 голос
/ 03 апреля 2014

Это старая ветка, но я отвечаю на нее, потому что не так много постов, касающихся SWIG.

Нацелиться конкретно на ситуацию выше

%typemap(in, numinputs=0) double PointB[3] {
  double tmp[3];
  $1 = tmp;
}

%typemap(argout) double PointB[3] {
  PyObject *o = PyList_New(3);
  int i;
  for(i=0; i<3; i++)
  {
    PyList_SetItem(o, i, PyFloat_FromDouble($1[i]));
  }
  $result = o;
}
1 голос
/ 07 сентября 2010

Вот одно решение, которое я нашел, но оно может быть не самым лучшим:

%typemap(in) double[ANY] (double temp[$1_dim0]) {
  int i;
  if (!PySequence_Check($input)) {
    PyErr_SetString(PyExc_ValueError,"Expected a sequence");
    return NULL;
  }
  if (PySequence_Length($input) != $1_dim0) {
    PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements");
    return NULL;
  }
  for (i = 0; i < $1_dim0; i++) {
    PyObject *o = PySequence_GetItem($input,i);
    if (PyNumber_Check(o)) {
      temp[i] = (double) PyFloat_AsDouble(o);
    } else {
      PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");      
      return NULL;
    }
  }
  $1 = temp;
}

Это пример документов, с которыми я наконец столкнулся, которые преобразуют списки Python в массивы.Следующая часть была сложнее, соединяя воедино несколько примеров, которые я мог бы преобразовать возвращаемый массив в список Python:

%typemap(argout) double PointB[3]{
    PyObject *o = PyList_New(3);
    int i;
    for(i=0; i<3; i++)
    {
        PyList_SetItem(o, i, PyFloat_FromDouble($1[i]));
    }
    $result = o;
}

Однако мне нужно создать один из них для каждого возвращаемого значения в API.Также я должен назвать его с фиктивным значением в качестве параметра:

point_b = convertAtoB(s, point_a, dummy)

Есть ли лучший способ?

...