2013-04-17 13 views
9

Ho un ++ biblioteca che attualmente ha alcuni metodi C all'interno del quale restituire un std::vector definito comeConvertire uno std :: vector a un array NumPy senza copiare i dati

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

Attualmente sto lavorando su avvolgendo l'intera libreria per Python usando SWIG e questo sta funzionando bene finora.

SWIG avvolge questa funzione getValues() in modo che restituisca una tupla Python. Il problema è nel mio codice lato Python che voglio convertire questo in un array NumPy. Certo che posso fare questo:

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

ma questo fa sì che tutte le voci del vettore originale da prima copiati in una tupla Python SWIG e poi di nuovo in un array di NumPy da me. Dato che questo vettore potrebbe essere molto grande, preferirei evitare di fare queste due copie e vorrei avere un modo per far sì che SWIG crei un wrapper numpy.array attorno ai dati vettoriali originali in memoria.

Ho letto la documentazione per numpy.i ma ciò indica esplicitamente che gli array di output non sono supportati poiché sembrano funzionare sotto l'ipotesi di array in stile C piuttosto che di vettori C++.

La struttura di dati sottostante di numpy.array è solo una matrice in stile C come lo è un C++ std :: vector, quindi mi auguro che sia possibile accedere agli stessi dati in memoria.

C'è un modo per rendere SWIG restituire un numpy.array che non copia i dati originali?

risposta

8

A quanto pare è banale "cast" di C++ vettore a (C) array, vedere risposta su questa domanda: How to convert vector to array in C++

successivo è possibile creare un array NumPy che utilizzerà tale matrice C senza copiare, vedere discussion here o google per PyArray_SimpleNewFromData.

Non mi aspetto che SWIG faccia tutto questo automaticamente, invece dovresti probabilmente scrivere un wrapper per la tua funzione getValues, come getValuesAsNumPyArray.

0

Sembra che PyArray_SimpleNewFromData richieda di eseguire la gestione della memoria; se la gestione della memoria è già gestito sul lato del C++, cioè, Python non è responsabile per la memoria, si può semplicemente utilizzare np.asarray per ottenere un allineamento NumPy che condivide la memoria con il vettore C++, in questo modo:

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]) 

La sezione "Wrapping C and C++ Arrays" del capitolo 10 del libro Cython di Kurt Smith fornisce buoni esempi al riguardo. Vedi anche Coercion to Numpy from official user guide.

+0

Ciò ha causato l'arresto anomalo di python. – snowleopard

Problemi correlati