2015-07-17 27 views
5

Ich versuche ein Python-Modul in C++ zu erstellen, das einen 2D-Vektor in ein Numpy-2D-Array umwandelt. Was ist hier falsch - vermutlich ist eine Transformation erforderlich, um ein Python-Objekt von PyObject * zu boosten?Python * boost :: python :: object

boost::python::object build_day(int year, int day) { 

    PyObject* arr; 
    const int HEIGHT = 5; 
    const int WIDTH = 5; 

    std::vector<std::vector<float> > array(WIDTH, std::vector<float>(HEIGHT)); 

    npy_intp dims[2] = {WIDTH, HEIGHT}; 
    arr = PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, &array); 

    return arr; 
} 

BOOST_PYTHON_MODULE(sumpar) { 
    using namespace boost::python; 
    def("build_day", build_day, args("year", "day")); 
} 

Antwort

4

Die boost::python::object bietet eine verallgemeinerte Schnittstelle zu Python-Objekte. Um einen aus einem PyObject* zu konstruieren, muss man zuerst einen boost::python::handle<> konstruieren, der im Wesentlichen ein Smart-Pointer ist, der entworfen wurde, um Referenz-gezählte Python-Objekte zu verwalten (PyObject* oder abgeleitete Typen). Häufig verwendet man handle<> zwischen der Grenze zwischen Boost.Pythons Code auf höherer Ebene und der Python/C-API.

namespace python = boost::python; 
PyObject* py_object = get_py_object(); 
python::handle<> handle(py_object); 
boost::python object(handle); 

Beachten Sie, dass die handle Eigentum an der PyObject* teilen, und während der Zerstörung, wird die Referenzzählung auf der PyObject sie managt verringern. Daher ist es wichtig, bei der Konstruktion anzugeben, ob handle<> die Referenzzahl von PyObject* erhöhen muss.

Wenn PyObject hat bereits seine Referenzzähler erhöht wird, dann verwenden:

namespace python = boost::python; 
PyObject* py_object = ...; 
python::handle<> handle(py_object); 
python::object object(handle); 

Wenn PyObject seine Referenzzähler nicht erhöht hatte, und der Griff muss es tun, dann verwenden Sie die borrowed() Funktion während der Bauphase:

namespace python = boost::python; 
PyObject* py_object = ...; 
python::handle<> handle(python::borrowed(py_object)); 
python::object object(handle); 

Hier ist ein komplettes Beispiel demonstrating eineKonstruktionvon einer PyObject*:

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

// Mocks... 
enum { NPY_FLOAT }; 
typedef int npy_intp; 
PyObject* PyArray_SimpleNewFromData(int, npy_intp*, int, void*) 
{ 
    return PyString_FromString("hello world"); 
} 

boost::python::object build_day(int year, int day) 
{ 
    const int HEIGHT = 5; 
    const int WIDTH = 5; 

    std::vector<std::vector<float> > array(
     WIDTH, std::vector<float>(HEIGHT)); 

    npy_intp dims[2] = {WIDTH, HEIGHT}; 

    namespace python = boost::python; 
    PyObject* arr = PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, &array); 
    python::handle<> handle(arr); 
    return python::object(handle); 
} 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    python::def("build_day", &build_day, python::args("year", "day")); 
} 

Interaktive Nutzung:

>>> import example 
>>> day = example.build_day(1, 2); 
>>> assert(day) 

Beachten Sie, dass ein minimales vollständiges Beispiel das obige Beispiel zu schaffen, hat verspottet PyArray_SimpleNewFromData(), die einfach Python-String zurückzugibt. Es ist wichtig, die Dokumentation zu Rate zu ziehen, um zu bestimmen, ob die PyObject* ausgeliehen ist oder nicht, und ob es lebenslange Anforderungen zwischen dem Objekt und seinen Argumenten gibt. Im Fall von PyArray_SimpleNewFromData() die PyObject* zurückgegeben:

  • hat bereits seine Referenzzählung
  • die Lebensdauer des zugrunde liegenden Speichers zu dem Array bereitgestellt erhöht muss mindestens so lang wie die zurück PyObject sein. Die build_day() Funktion in der ursprünglichen Frage erfüllt diese Anforderung nicht.
0

Mein Vorschlag ist, die Variablen und Objekte, die von boost :: Python nutzen, wenn Sie also ein Array an die Python zurückkehren möchte, sollte sein kann es eine gute Idee wäre, einen Schub zu verwenden :: Python :: dict, so etwas wie ...

boost::python::dict arr; 

int i = 0; 
for (auto &item: array) { 
    arr[i] = item; 
    ++i; 
} 

return arr; 
Verwandte Themen