有没有办法使用pythonappend与SWIG的新的内置function?

我有一个与SWIG合作的小项目。 特别是,我的一些函数返回std::vector s,它被转换成Python中的元组。 现在,我做了很多数字,所以我只是让SWIG在从c ++代码返回之后将它们转换为numpy数组。 要做到这一点,我在SWIG中使用类似下面的内容。

 %feature("pythonappend") My::Cool::Namespace::Data() const %{ if isinstance(val, tuple) : val = numpy.array(val) %} 

(实际上,有几个函数名为Data,其中一些返回浮点数,这就是为什么我检查val实际上是一个元组)。

但是,我也想使用现在可用的-builtin标志。 对这些数据函数的调用是很less见的,而且大部分是交互式的,所以它们的慢度不是问题,但是还有其他的慢速循环会随着内置选项而显着加速。

问题是,当我使用该标志时,pythonappendfunction被忽略。 现在,Data只是再次返回一个元组。 有什么办法,我仍然可以返回numpy数组? 我尝试使用types映射,但它变成了一个巨大的混乱。

编辑:

Borealid非常好地回答了这个问题。 只是为了完整性,我包含了一些相关的,但我需要的,因为我通过const引用返回,并使用vector向量(不要开始!),因此我需要微妙的不同的types映射。 这些是不同的,我不希望其他任何人试图找出微小的差异。

 %typemap(out) std::vector<int>& { npy_intp result_size = $1->size(); npy_intp dims[1] = { result_size }; PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_INT); int* dat = (int*) PyArray_DATA(npy_arr); for (size_t i = 0; i < result_size; ++i) { dat[i] = (*$1)[i]; } $result = PyArray_Return(npy_arr); } %typemap(out) std::vector<std::vector<int> >& { npy_intp result_size = $1->size(); npy_intp result_size2 = (result_size>0 ? (*$1)[0].size() : 0); npy_intp dims[2] = { result_size, result_size2 }; PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_INT); int* dat = (int*) PyArray_DATA(npy_arr); for (size_t i = 0; i < result_size; ++i) { for (size_t j = 0; j < result_size2; ++j) { dat[i*result_size2+j] = (*$1)[i][j]; } } $result = PyArray_Return(npy_arr); } 

编辑2:

虽然不是我所期望的,但类似的问题也可以用@ MONK的方法解决( 在这里解释 )。

我同意你的看法,使用typemap变得有点混乱,但是这是完成这个任务的正确方法。 你也是对的,SWIG文档并不直接说%pythonappend-builtin不兼容,但它强烈暗示: %pythonappend 添加到Python代理类中 ,并且Python代理类根本不存在-builtin标志。

之前,你正在做的是让SWIG将C ++ std::vector对象转换成Python元组,然后将这些元组传递回numpy – 在那里再次进行转换。

你真正想要做的是在C级别转换一次。

这里有一些代码将把所有的std::vector<int>对象转换为NumPy整型数组:

 %{ #include "numpy/arrayobject.h" %} %init %{ import_array(); %} %typemap(out) std::vector<int> { npy_intp result_size = $1.size(); npy_intp dims[1] = { result_size }; PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_INT); int* dat = (int*) PyArray_DATA(npy_arr); for (size_t i = 0; i < result_size; ++i) { dat[i] = $1[i]; } $result = PyArray_Return(npy_arr); } 

这使用C级numpy函数来构造和返回一个数组。 为了,它:

  • 确保NumPy的arrayobject.h文件包含在C ++输出文件中
  • 导致在加载Python模块时调用import_array (否则所有的Nu​​mPy方法都会出现段错误)
  • 使用types映射将std::vector<int>任何返回映射到NumPy数组typemap

这个代码应该放在你%import包含返回std::vector<int>的函数的头文件之前 。 除了这个限制之外,它完全是独立的,所以它不应该在代码库中增加太多主观的“混乱”。

如果您需要其他vectortypes,只需更改NPY_INT和所有int*int位,否则复制上面的函数。