2011-05-27 27 views
30

Tengo un método en C++ que se llama desde python y necesita devolver un objeto de lista de python.std :: vector to boost :: python :: list

Ya he creado el método, y está adjunto a una clase expuesta y se puede llamar desde python en este momento ... (devuelve vacío).

Entonces la pregunta es, ¿Cómo se crea una lista de pitón de esto:

std::vector<std::string> results;

Realmente no soy la comprensión de cómo el constructor funciona de esta documentación:

http://www.boost.org/doc/libs/1_37_0/libs/python/doc/v2/list.html

Además ... Realmente no quiero devolver el tipo de vector envuelto ... Solo quiero crear una nueva lista de python con los valores de cadena del vector.

Mis disculpas si esto es un duplicado ... Encontré algunas listas para las preguntas del vector, pero no pude encontrar ninguna sobre la creación de una nueva lista de Python.

que podría ampliar esta pregunta para incluir algunas otras preguntas como:

Creación de un nuevo diccionario de Python desde un: std::map<std::string, std::string> y así sucesivamente.

+0

vi esta pregunta: http://stackoverflow.com/questions/3240971/does-boost-python-support-a-function- return-a-vector-by-ref-or-value Pero eso estaba hablando de devolver un vector envuelto ... Solo quiero crear un nuevo objeto python y devolverlo. – mcot

+0

duplicado posible: http://stackoverflow.com/q/5314319/198633 – inspectorG4dget

Respuesta

11

que tienen esta función utilizando iteradores para convertir std::vector a py::list:

namespace py = boost::python; 

template<class T> 
py::list std_vector_to_py_list(const std::vector<T>& v) 
{ 
    py::object get_iter = py::iterator<std::vector<T> >(); 
    py::object iter = get_iter(v); 
    py::list l(iter); 
    return l; 
} 
+0

no tiene esto una carga masiva? Es realmente una pregunta –

+3

Intenté esto, obtengo una excepción en 'py :: object iter = get_iter (v)': 'No to_python (by-value) converter found for C++ type: class std :: vector > 'a partir de Boost 1.51 –

+4

del mismo modo 'No to_python (by-value) converter found for C++ type: std :: vector >', boost 1.48 –

44

boost::python ya incluye funcionalidad para envolver vectores y mapas. Aquí es código de ejemplo para los vectores, como se puede ver tanto pasando y volviendo listas es bastante simple:

// C++ code 
typedef std::vector<std::string> MyList; 
class MyClass { 
    MyList myFuncGet(); 
    void myFuncSet(const Mylist& list); 
    //  stuff 
}; 

// Wrapper code 

#include <boost/python/suite/indexing/vector_indexing_suite.hpp> 

using namespace boost::python; 


BOOST_PYTHON_MODULE(mymodule) 
{ 
    class_<MyList>("MyList") 
     .def(vector_indexing_suite<MyList>()); 

    class_<MyClass>("MyClass") 
     .def("myFuncGet", &MyClass::myFuncGet) 
     .def("myFuncSet", &MyClass::myFuncSet) 
     ; 
} 

Los mapas son muy similares a los vectores y se describen en este post: Boost::Python- possible to automatically convert from dict --> std::map?

Desafortunadamente boost::python no tiene actualmente incluir instalaciones para listas de envolver. Puedes crear el contenedor manualmente, pero estoy fuera de tiempo por esta respuesta. Puedo publicarlo hoy o mañana. Apreciaría una nueva pregunta sobre este problema en particular, porque la respuesta será bastante extensa y probablemente esté fuera del alcance de esta publicación. Solo evitaría listas y usar vectores en su lugar.

+0

hola @Aleksey, creo que tengo una pregunta relacionada para que [link] (http://stackoverflow.com/q/6776888/814180) –

8

Si sólo desea crear una lista de pitón manualmente (y tienen la py :: Lista de retorno de la función en lugar de vector), hacerlo de esta manera:

/* using namespace std; namespace py=boost::python; 
    #define FOREACH BOOST_FOREACH 
*/ 
vector<string> ss; 
py::list ret; 
FOREACH(const string& s, ss) ret.append(s); 
return s; 

Para conversiones automáticas, defina el convertidor para el vector de lista de Python a C++ y de C++ a la lista de Python - Acabo de escribir sobre eso en Instantiating shared_ptr's in boost::python (la segunda parte de la respuesta); de esa manera, obtienes listas realmente de pitones.

Otra posibilidad para la conversión automática (con la que no tengo experiencia) es usar indexing_suite, que incluirá vector<string> como una clase especial en python, como un colega mencionado aquí.

1

Fwiw, aquí es una función de plantilla en la misma línea que la solución Eudoxos':

namespace py = boost::python; 

template<class T> 
py::list std_vector_to_py_list(const std::vector<T>& v) 
{ 
    py::list l; 
    typename std::vector<T>::const_iterator it; 
    for (it = v.begin(); it != v.end(); ++it) 
    l.append(*it); 
    return l; 
} 
+0

Esto copia los valores como se agrega a la lista, ¿verdad? ¿Hay alguna forma de evitar eso (suponiendo que los valores sean de algún tipo de clase), entonces en python 'get_list (0) == get_list (0)' devuelve true? Algo como 'bp :: reference_existing_object' pero dentro de la función? – GaryO

6

De http://gist.github.com/octavifs/5362272:

// Converts a C++ vector to a python list 
template <class T> 
boost::python::list toPythonList(std::vector<T> vector) { 
    typename std::vector<T>::iterator iter; 
    boost::python::list list; 
    for (iter = vector.begin(); iter != vector.end(); ++iter) { 
     list.append(*iter); 
    } 
    return list; 
} 
+1

Éste funciona, a diferencia del anwser @rafak. Gracias. – Marcin

+0

Sí, funciona, pero no estoy seguro de si hay demasiada sobrecarga al tener que iterar el vector y anexar cada elemento. ¿Tal vez usar una matriz numpy es más eficiente? – user819893

1

Yo uso following utili ty funciones para convertir de/a contenedores stl. La función de suma trivial ilustra cómo se usan. También encontré siguiente paquete de código abierto que tiene un buen número de utilidades de conversión: https://github.com/cctbx/cctbx_project/tree/master/scitbx/boost_python

#include <vector> 
#include <boost/python.hpp> 
#include <boost/python/object.hpp> 
#include <boost/python/stl_iterator.hpp> 

namespace bpy = boost::python; 

namespace fm { 

template <typename Container> 
bpy::list stl2py(const Container& vec) { 
    typedef typename Container::value_type T; 
    bpy::list lst; 
    std::for_each(vec.begin(), vec.end(), [&](const T& t) { lst.append(t); }); 
    return lst; 
} 

template <typename Container> 
void py2stl(const bpy::list& lst, Container& vec) { 
    typedef typename Container::value_type T; 
    bpy::stl_input_iterator<T> beg(lst), end; 
    std::for_each(beg, end, [&](const T& t) { vec.push_back(t); }); 
} 

bpy::list sum(const bpy::list& lhs, const bpy::list& rhs) { 
    std::vector<double> lhsv; 
    py2stl(lhs, lhsv); 

    std::vector<double> rhsv; 
    py2stl(rhs, rhsv); 

    std::vector<double> result(lhsv.size(), 0.0); 
    for (int i = 0; i < lhsv.size(); ++i) { 
    result[i] = lhsv[i] + rhsv[i]; 
    } 
    return stl2py(result); 
} 

} // namespace fm 

BOOST_PYTHON_MODULE(fm) 
{ 
    bpy::def("sum", &fm::sum); 
} 
Cuestiones relacionadas