我有一个使用SWIG非常成功的小项目。特别是,我的一些函数返回std::vector
,在Python中会被转换成元组(tuples)。由于我的项目需要进行很多数值计算,所以在从C++代码返回数据后,我直接让SWIG将其转换成numpy数组。为了做到这一点,在SWIG中我使用类似以下的东西。
%feature("pythonappend") My::Cool::Namespace::Data() const %{ if isinstance(val, tuple) : val = numpy.array(val) %}
(实际上,有几个名为Data的函数,其中一些返回浮点数,这就是为什么我要检查val
是否真的是一个元组的原因。) 这很好地解决了问题。
但是,我也想使用现在可用的-builtin
标志。对这些Data函数的调用很少,并且大多数是交互式的,因此它们的慢速不是问题,但是还有其他缓慢的循环,内置选项可以显著加快速度。
问题是当我使用该标志时,pythonappend功能会被默默忽略。现在,Data再次只返回一个元组。我是否有任何方法仍然可以返回numpy数组?我尝试使用typemaps,但变成了一个混乱。
编辑:
Borealid非常好地回答了这个问题。为了完整起见,我包括了一些相关但微妙不同的typemap,因为我通过const引用返回并使用vector的向量(不要开始!)。 这些差异足以使任何人在尝试弄清楚细微差别时都不会感到困难。
%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的方法进行解决(在此处解释)。
-builtin
会忽略 pythonappend。我无法应对将std::vector
映射到 numpy 数组的挑战。我进行了分析,它显著加速了我的接口中最烦人的循环(不够长,不能休息;太长而无法频繁等待)。但我也意识到我可以将这个循环移到我的 C++ 代码中,尽管有点笨拙。所以我会这样做。不过,你的“两个模块”的建议很有意思,在其他情况下可能也很有用。 - Mike-Wall
选项,也没有警告(虽然这是一个非常大的忽略,我认为甚至不需要这个选项)。 - MikeData
方法? - Paul Price