有没有办法使用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
(否则所有的NumPy方法都会出现段错误) - 使用types映射将
std::vector<int>
任何返回映射到NumPy数组typemap
这个代码应该放在你%import
包含返回std::vector<int>
的函数的头文件之前 。 除了这个限制之外,它完全是独立的,所以它不应该在代码库中增加太多主观的“混乱”。
如果您需要其他vectortypes,只需更改NPY_INT
和所有int*
和int
位,否则复制上面的函数。