У меня есть библиотека C ++, которая в настоящее время имеет несколько методов, которые возвращают std::vector
определяется как
public:
const std::vector<uint32_t>& getValues() const;
В настоящее время я работаю над переносом всей библиотеки для Python с использованием SWIG, и пока это работает хорошо.
SWIG оборачивает это getValues()
Функция отлично, так что он возвращает кортеж Python. Проблема в моем Python-коде, который я хочу преобразовать в массив NumPy. Конечно, я могу сделать это:
my_array = np.array(my_object.getValues(), dtype='uint32')
но это приводит к тому, что все записи в исходном векторе сначала копируются в кортеж Python SWIG, а затем снова в массив numpy. Поскольку этот вектор может быть очень большим, я бы предпочел не делать эти две копии и хотел бы, чтобы SWIG создал оболочку numpy.array вокруг исходных векторных данных в памяти.
Я прочитал документацию для numpy.i но в нем явно упоминается, что выходные массивы не поддерживаются, поскольку они, похоже, работают в предположении массивов в стиле C, а не векторов C ++.
Базовая структура данных numpy.array — это просто массив в стиле C, как и C ++ std :: vector, поэтому я надеюсь, что тогда будет возможно получить доступ к тем же данным в памяти.
Есть ли способ заставить SWIG возвращать numpy.array, который не копирует исходные данные?
Очевидно, тривиально «привести» вектор C ++ к массиву (C), см. Ответ на этот вопрос: Как преобразовать вектор в массив в C ++
Далее вы можете создать пустой массив, который будет использовать этот массив C без копирования, см. обсуждение здесь, или Google для PyArray_SimpleNewFromData
,
Я не ожидал бы, что SWIG сделает все это для вас автоматически, вместо этого вы, вероятно, должны написать оболочку для своей функции getValues
себя, что-то вроде getValuesAsNumPyArray
,
Это похоже на PyArray_SimpleNewFromData
потребует от вас сделать свое собственное управление памятью; если управление памятью уже выполняется на стороне C ++, то есть Python не отвечает за память, вы можете просто использовать np.asarray
чтобы получить массив NumPy, который разделяет память с вектором C ++, вот так:
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])
В разделе «Обтекание массивов C и C ++» в главе 10 книги Курта Смита «Cython» приведены хорошие примеры этого. Также см Принуждение к Numpy из официального руководства пользователя.