Wie kann man die vom Typ überladenen Funktionen umhüllen?

Angenommen, es gibt eine Klasse MyArray die ein Array von SomeType . Es ist in C ++ geschrieben und in Python mit boost :: python gewickelt.

 BOOST_PYTHON_MODULE(my_array_module) { class_<MyArray>("MyArray") // a few '.def's ... .def("__getitem__", ???) ; } 

Die Funktion __getitem__ in Python kann entweder einen Index nehmen und den SomeType Wert zurückgeben oder ein Slice-Objekt nehmen und das Slice zurückgeben.

Es gibt, wie man mit Funktionen überfüllt, die in C ++ überladen sind, um sie in verschiedene Python-Funktionen zu verpacken. Es gibt, wie man eine überladene Funktion in Python macht, wenn Überlastung bedeutet verschiedene Anzahl von Args.

Aber wie man überladene Funktionen umgibt, wenn sie sich durch Ariktentypen unterscheiden? Ich benötige 2 getitem Funktionen in C ++.

 const SomeType& getitem(PyObject *self, size_t pos) { // ... } MyArray getitem(PyObject *self, slice sl) { // ... } 

Wenn du versuchst, es mit dem BOOST_PYTHON_FUNCTION_OVERLOADS beschriebenen BOOST_PYTHON_FUNCTION_OVERLOADS zu verpacken, wird es nicht kompiliert.

Ich könnte eine Funktion machen

 PyObject* getitem(PyObject *self, PyObject *pos_or_slice) { extract<size_t> get_pos(pos_or_slice); if (get_pos.check()) { // return a single item (SomeType) } else { // return a slice (MyArray) } } 

Aber ich habe keine Ahnung, wie man MyArray in PyObject* richtig MyArray PyObject* , so dass es mit der von class_ generierten Umhüllung class_ .

One Solution collect form web for “Wie kann man die vom Typ überladenen Funktionen umhüllen?”

Kurz gesagt, solange die C ++ – Funktionen unterschiedliche Parametertypen haben, kann jede Funktion als dieselbe Pythonfunktion mit separaten Aufrufen von def() ausgesetzt werden. Boost.Python wird das Dispatching auf der Grundlage von Typ Conversions behandeln. Wenn die Typen zweideutig sind, dann muss man oft eine Hilfsfunktion erstellen und aussetzen, die das Versenden manuell bearbeitet, basierend auf der Inspektion der boost::python::object Argumente.


Hier ist ein komplettes minimales Beispiel, das den Zugriff auf eine Mockup- Counter Klasse-Daten entweder über einen Index oder ein Slice demonstriert:

 #include <vector> #include <boost/range/algorithm.hpp> #include <boost/range/irange.hpp> #include <boost/python.hpp> #include <boost/python/slice.hpp> /// @brief Mockup class that creates a range from 0 to N. struct counter { counter(std::size_t n) { data.reserve(n); boost::copy(boost::irange(std::size_t(0), n), std::back_inserter(data)); } std::vector<int> data; }; /// @brief Handle index access for counter object. int spam_getitem_index(const counter& self, int index) { // Attempt to convert to positive index. if (index < 0) { index += self.data.size(); } // Check for valid range. if (index < 0 || self.data.size() <= index) { throw std::out_of_range("counter index out of range"); } return self.data[index]; } /// @brief Handle slicing for counter object. boost::python::list spam_getitem_slice( const counter& self, boost::python::slice slice) { namespace python = boost::python; python::list result; // Boost.Python will throw std::invalid_argument if the range would be // empty. python::slice::range<std::vector<int>::const_iterator> range; try { range = slice.get_indices(self.data.begin(), self.data.end()); } catch (std::invalid_argument) { return result; } // Iterate over fully-closed range. for (; range.start != range.stop; std::advance(range.start, range.step)) { result.append(*range.start); } result.append(*range.start); // Handle last item. return result; } BOOST_PYTHON_MODULE(example) { namespace python = boost::python; python::class_<counter>("Counter", python::init<int>()) .def("__getitem__", &spam_getitem_slice) .def("__getitem__", &spam_getitem_index) ; } 

Interaktiver Einsatz:

 >>> from example import Counter >>> counter = Counter(5) >>> assert(counter[:] == [0,1,2,3,4]) >>> assert(counter[:-2] == [0,1,2]) >>> assert(counter[-2:] == [3,4]) >>> assert(counter[::2] == [0,2,4]) >>> assert(counter[1::2] == [1,3]) >>> assert(counter[100:] == []) >>> assert(counter[1] == 1) >>> assert(counter[-1] == 4) >>> counter[100] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: counter index out of range >>> counter[-100] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: counter index out of range 

Beachten Sie, wie spam_getitem_index() eine std::out_of_range Ausnahme auslöst. Boost.Python übersetzt die zugehörige IndexError Python-Ausnahme.

Python ist die beste Programmiersprache der Welt.