有没有办法使用SWIG将不同的数组类型从python传递到c ++?

时间:2013-07-08 21:03:37

标签: c++ python c numpy swig

我想使用SWIG将c ++函数传递给python,它输入一个双数组和一个整数数组。有没有办法做到这一点?

例如,我有一个c ++函数,它接受一个double和一个int数组:

double myfun(double* a, int n, int* b, int m){...}

在SWIG界面文件中,我尝试编写

%apply (double* IN_ARRAY1, int DIM1, int* IN_ARRAY1, int DIM1) {(double* a, int n, int* b, int m)}

但没有运气。它已编译,但我无法在python中调用myfun函数,如

myfun(a,b) 

其中a是双numpy数组,b是整数numpy数组。我在python中遇到以下错误:

myfun() takes exactly 4 arguments (2 given)

有什么建议吗?这甚至可能吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

简短的回答是你需要使用一个带有两个输入的typemap,但是numinputs属性设置为1,例如:

%module test

%typemap(in,numinputs=1) (double *a, size_t) %{
  assert(PyList_Check($input));
  $2 = PyList_Size($input);
  $1 = malloc(sizeof *$1 * $2);
  for(size_t i = 0; i < $2; ++i) {
    $1[i] = PyFloat_AsDouble(PyList_GetItem($input, i));
  }
%}

%typemap(in, numinputs=1) (int *b, size_t) %{
  assert(PyList_Check($input));
  $2 = PyList_Size($input);
  $1 = malloc(sizeof *$1 * $2);
  for (size_t i = 0; i < $2; ++i) {
    $1[i] = PyInt_AsLong(PyList_GetItem($input, i));
  }
%}

%typemap(freearg) (double *a, size_t) %{
  free($1);
%}

%typemap(freearg) (int *b, size_t) %{
  free($1);
%}

%inline %{
  double myfun(double *a, size_t n, int *b, size_t m) {
    (void)a; (void) b;
    printf("%d, %d\n", n, m);
    for (size_t i = 0; i < (n > m ? n : m); ++i) {
      printf("%d: %f - %d\n", i, i < n ? a[i] : 0, i < m ? b[i] : 0);
    }
    return 1.0;
  }
%}

这样可行,每对(array,len)都有一个typemap,足以用作:

import test

a = [0.5, 1.0, 1.5]
b = [1,2,3]

test.myfun(a,b)

我们可以使用alloca或C99的VLA功能来避免需要malloc来电,但为了便于说明,这是有效的。

(注意:你没有在函数原型中的任何地方写const,但暗示是它没有修改输入数组。如果不是这样的话那么你需要编写一个相应的argout typemap从已分配的数组复制回Python列表。

然而,它也是非常重复的,所以如果我们可以在两者之间共享一些代码可能会更好 - 如果需要,你可以使用一些更高级的SWIG功能。如果需要,您还可以添加对memory views的支持,而不仅仅是列表。