web-dev-qa-db-fra.com

std :: vecteur pour booster :: python :: list

J'ai une méthode en c ++ qui est appelée depuis python et doit renvoyer un objet de liste python).

J'ai déjà créé la méthode, et son attaché à une classe exposée et appelable depuis python en ce moment ... (il retourne void).

La question est donc de savoir comment créer une liste python à partir de ceci:

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

Je ne comprends pas vraiment comment fonctionne le constructeur à partir de cette documentation:

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

Aussi ... Je ne veux pas vraiment retourner le type de vecteur enveloppé ... Je veux juste créer une nouvelle liste python avec les valeurs de chaîne du vecteur.

Mes excuses s'il s'agit d'un doublon ... J'ai trouvé pas mal de liste de questions vectorielles mais je n'ai trouvé aucune sur la création d'une nouvelle liste python.

Je pourrais développer cette question pour inclure d'autres questions comme:

Création d'un nouveau dictionnaire python à partir d'un: std::map<std::string, std::string> etc.

40
mcot

J'ai cette fonction en utilisant des itérateurs pour convertir std::vector à 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;
}
14
rafak

boost::python inclut déjà des fonctionnalités pour encapsuler les vecteurs et les cartes. Voici un exemple de code pour les vecteurs, comme vous pouvez le voir à la fois en passant et en retournant des listes est assez 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)
        ;
}

Les cartes sont très similaires aux vecteurs et sont décrites dans cet article: Boost :: Python - possible de convertir automatiquement depuis dict -> std :: map?

Malheureusement boost::python n'inclut pas actuellement les possibilités de wrapping des listes. Vous pouvez créer le wrapper manuellement, mais je n'ai plus de temps pour cette réponse. Je peux le poster aujourd'hui ou demain. J'apprécierais une nouvelle question sur ce problème particulier, parce que la réponse sera assez complète et est probablement en dehors de la portée de cet article. Je voudrais juste éviter les listes et utiliser des vecteurs à la place.

61

Si vous voulez seulement créer la liste python manuellement (et que la fonction retourne py :: list plutôt que vector), faites-le comme ceci:

/* 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;

Pour les conversions automatiques, définissez le convertisseur pour le vecteur de python en c ++ et de c ++ en python - je viens d'écrire à ce sujet sur Instanciation de shared_ptr dans boost :: python (la deuxième partie de la réponse); de cette façon, vous obtenez vraiment python listes).

Une autre possibilité de conversion automatique (avec laquelle je n'ai aucune expérience) consiste à utiliser indexing_suite, qui encapsulera vector<string> comme classe spéciale en python, comme un collègue déjà mentionné ici.

8
eudoxos

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;
}
6
o.z

FWIW, voici une fonction de modèle dans la même veine que la solution d'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;  
}
1
Rob Agar

J'utilise les fonctions utilitaires suivantes pour convertir de/vers des conteneurs stl. La fonction somme triviale illustre comment ils sont utilisés. J'ai également trouvé le package opensource suivant qui contient de nombreux utilitaires de conversion: 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);
}
1
Validus Oculus