提问者:小点点

将std::向量转换为NumPy数组而不复制数据


我有一个C库,目前有一些方法里面返回一个std::向量定义如下

public:
  const std::vector<uint32_t>& getValues() const;

我目前正在使用SWIG包装整个库Python,到目前为止效果很好。

SWIG很好地包装了这个getValue()函数,使其返回一个Python元组。问题出在我的Python端代码中,我想将其转换为NumPy数组。当然,我可以通过以下方式做到这一点:

my_array = np.array(my_object.getValues(), dtype='uint32')

但是这会导致原始向量中的所有条目首先被SWIG复制到一个Python元组中,然后被我再次复制到一个numpy数组中。由于这个向量可能非常大,我宁愿避免制作这两个副本,并希望有一种方法让SWIG在内存中的原始向量数据周围创建一个numpy.数组包装器。

我已经阅读了numpy. i的留档,但它明确提到不支持输出数组,因为它们似乎在C样式数组而不是C向量的假设下工作。

numpy. array的底层数据结构只是一个C样式的数组,就像C std::向量一样,所以我希望在内存中访问相同的数据是可行的。

有没有办法让SWIG返回一个不复制原始数据的numpy. array?


共2个答案

匿名用户

显然将C向量“转换”为(C)数组是微不足道的,请参阅此问题的答案:如何在C中将向量转换为数组

接下来,您可以创建一个numpy数组,它将使用该C数组而无需复制,请参阅此处的讨论,或google forPyArray_SimpleNewFromData

我不希望SWIG自动为您完成所有这些,相反,您可能应该自己为您的函数getValue编写一个包装器,例如getValuesAsNumPyArray

匿名用户

似乎PyArray_SimpleNewFromData会要求你自己进行内存管理;如果内存管理已经在C端处理,也就是说,Python不负责内存,你可以使用np. asars得到一个与C向量共享内存的numpy数组,如下所示:

from libcpp.vector cimport vector
import numpy as np
cdef vector[double] vec
vec.push_back(1)
vec.push_back(2)
cdef double *vec_ptr = &vec[0]    # get hold of data array underlying vec; also vec.data() if you have C++11
cdef double[::1] vec_view = <double[:vec.size()]>vec_ptr    # cast to typed memory view
vec_npr = np.asarray(vec_view)    # get numpy array from memory view
print(vec_npr)    # array([1.0, 2.0])

Kurt Smith的Cython书第10章中的“包装C和C数组”部分提供了很好的例子。另请参阅官方用户指南中的Coercion to Numpy。