2010-09-21 11 views
20

Schließlich kann ich std :: vector in Python mit dem Operator [] verwenden. Der Trick ist, einfach ++ Wrapper einen Container in dem Boost-C zur Verfügung stellen, die das interne Vektor-Material behandelt:boost :: python: Python-Liste zu std :: vector

#include <boost/python.hpp> 
#include <vector> 
class world 
{ 
    std::vector<double> myvec; 

    void add(double n) 
    { 
     this->myvec.push_back(n); 
    } 

    std::vector<double> show() 
    { 
    return this->myvec; 
    } 
}; 

BOOST_PYTHON_MODULE(hello) 
{ 
    class_<std::vector<double> >("double_vector") 
     .def(vector_indexing_suite<std::vector<double> >()) 
    ; 

    class_<World>("World") 
    .def("show", &World::show) 
     .def("add", &World::add) 
    ; 
} 

Die andere Herausforderung ist: Howto übersetzt Python-Listen in std :: Vektoren? Ich habe versucht, eine C++ Klasse erwartet einen std :: vector als Parameter hinzuzufügen und hinzugefügt, um den entsprechenden Wrapper-Code:

#include <boost/python.hpp> 
#include <vector> 
class world 
{ 
    std::vector<double> myvec; 

    void add(double n) 
    { 
     this->myvec.push_back(n); 
    } 

    void massadd(std::vector<double> ns) 
    { 
     // Append ns to this->myvec 
    } 

    std::vector<double> show() 
    { 
    return this->myvec; 
    } 
}; 

BOOST_PYTHON_MODULE(hello) 
{ 
    class_<std::vector<double> >("double_vector") 
     .def(vector_indexing_suite<std::vector<double> >()) 
    ; 

    class_<World>("World") 
    .def("show", &World::show) 
     .def("add", &World::add) 
     .def("massadd", &World::massadd) 
    ; 
} 

Aber wenn so zu tun, ich am Ende mit dem folgende Boost.Python.ArgumentError:

>>> w.massadd([2.0,3.0]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
Boost.Python.ArgumentError: Python argument types in 
    World.massadd(World, list) 
did not match C++ signature: 
    massadd(World {lvalue}, std::vector<double, std::allocator<double> >) 

Kann mir jemand sagen, wie ich auf Python-Listen innerhalb meiner C++ - Funktion zugreifen kann?

Danke, Daniel

Antwort

23

Um Ihre C++ Methode akzeptieren Python listet Sie sollten boost::python::list

void massadd(boost::python::list& ns) 
{ 
    for (int i = 0; i < len(ns); ++i) 
    { 
     add(boost::python::extract<double>(ns[i])); 
    } 
} 
+0

'boost :: python :: list' kann heterogen sein, und Sie müssen Ausnahmen von' extract' abfangen. – eudoxos

+0

meine Entschuldigung, Ausnahme von 'extrahieren' wird automatisch in Python übersetzt. Es tut uns leid. – eudoxos

+4

Ja schön und einfach zu tun, nur die Boost-Python-Dokumentation ist so schlecht, und Operator [] ist in einer Vorlage versteckt object_operators mehrere Ebenen in der Hierarchie und nicht offensichtlich eine Operation eine Liste. Ich habe ihre Website-Dokumentation nicht freundlicher gefunden. Len() eine externe Methode zu machen ist nicht so cool, wie sie denken, dass es entweder ist. Plus ist dies der einzige Weg, um durchzulaufen? – CashCow

1

Um die automatische Konvertierung von Python-Listen, ist ein Konverter definieren bedienen, die

  1. prüft, ob die Liste in Ihren Typ konvertierbar ist (dh dass es sich um eine Sequenz handelt; zusätzlich können Sie auch prüfen, ob alle Elemente re sind) gewünschter Typ, der aber auch im zweiten Schritt behandelt werden kann)
  2. gibt das neue Objekt zurück, wenn der erste Schritt erfolgreich war; Exception auslösen, wenn ein Sequenzelement nicht zu dem konvertiert werden kann, was Sie benötigen.

Ich kann jetzt nicht irgendetwas anderes als mein Code finden, können Sie kopieren & Paste this template (es am Ende der Datei für verschiedene enthaltenen Typen spezialisiert ist).

17

Hier ist, was ich benutze:

#include <boost/python/stl_iterator.hpp> 

namespace py = boost::python; 

template< typename T > 
inline 
std::vector<T> to_std_vector(const py::object& iterable) 
{ 
    return std::vector<T>(py::stl_input_iterator<T>(iterable), 
          py::stl_input_iterator<T>()); 
} 

Sollten Sie den Eingabetyp finden (py :: Objekt) zu liberal, fühlt sich frei, strengeren Typen angeben (py :: Liste in Ihrem Fall).

3

Basierend auf den obigen Antworten, die ich aus einem C++ Funktion ein Beispiel für den Zugriff auf Python-Listen in C++ sowie die Rückkehr eine Python-Liste erstellt:

#include <boost/python.hpp> 
#include <string> 

namespace py = boost::python; 

// dummy class 
class drow{ 
    public: 
     std::string word; 
     drow(py::list words); 
     py::list get_chars(); 
}; 

// example of passing python list as argument (to constructor) 
drow::drow(py::list l){ 
    std::string w; 
    std::string token; 
    for (int i = 0; i < len(l) ; i++){ 
     token = py::extract<std::string>(l[i]); 
     w += token; 
    } 
    this -> word = w; 
} 

// example of returning a python list 
py::list drow::get_chars(){ 
    py::list char_vec; 
    for (auto c : word){ 
     char_vec.append(c); 
    } 
    return char_vec; 
} 

// binding with python 
BOOST_PYTHON_MODULE(drow){ 
    py::class_<drow>("drow", py::init<py::list>()) 
     .def("get_chars", &drow::get_chars); 
} 

Für ein Build Beispiel und einen Test Python-Skript einen Blick here

Vielen Dank Arlaharen & rdesgroppes für die Zeiger (Wortspiel nicht beabsichtigt).